* fix broken links * update broken links utility * add missing payment evens * generate llms * fix segment link
659 lines
22 KiB
Plaintext
659 lines
22 KiB
Plaintext
---
|
|
sidebar_label: "Extend Customer"
|
|
tags:
|
|
- customer
|
|
- tutorial
|
|
- extend module
|
|
- server
|
|
---
|
|
|
|
import { Prerequisites } from "docs-ui"
|
|
|
|
export const metadata = {
|
|
title: `Extend Customer Data Model`,
|
|
}
|
|
|
|
# {metadata.title}
|
|
|
|
In this documentation, you'll learn how to extend a data model of the Customer Module to add a custom property.
|
|
|
|
You'll create a `Custom` data model in a module. This data model will have a `custom_name` property, which is the property you want to add to the [Customer data model](/references/customer/models/Customer) defined in the Customer Module.
|
|
|
|
You'll then learn how to:
|
|
|
|
- Link the `Custom` data model to the `Customer` data model.
|
|
- Set the `custom_name` property when a customer is created or updated using Medusa's API routes.
|
|
- Retrieve the `custom_name` property with the customer's details, in custom or existing API routes.
|
|
|
|
<Note title="Tip">
|
|
|
|
Similar steps can be applied to the `CustomerAddress` data model.
|
|
|
|
</Note>
|
|
|
|
## Step 1: Define Custom Data Model
|
|
|
|
Consider you have a Hello Module defined in the `/src/modules/hello` directory.
|
|
|
|
<Note title="Tip">
|
|
|
|
If you don't have a module, follow [this guide](!docs!/learn/fundamentals/modules) to create one.
|
|
|
|
</Note>
|
|
|
|
To add the `custom_name` property to the `Customer` data model, you'll create in the Hello Module a data model that has the `custom_name` property.
|
|
|
|
Create the file `src/modules/hello/models/custom.ts` with the following content:
|
|
|
|
```ts title="src/modules/hello/models/custom.ts"
|
|
import { model } from "@medusajs/framework/utils"
|
|
|
|
export const Custom = model.define("custom", {
|
|
id: model.id().primaryKey(),
|
|
custom_name: model.text(),
|
|
})
|
|
```
|
|
|
|
This creates a `Custom` data model that has the `id` and `custom_name` properties.
|
|
|
|
<Note title="Tip">
|
|
|
|
Learn more about data models in [this guide](!docs!/learn/fundamentals/modules#1-create-data-model).
|
|
|
|
</Note>
|
|
|
|
---
|
|
|
|
## Step 2: Define Link to Customer Data Model
|
|
|
|
Next, you'll define a module link between the `Custom` and `Customer` data model. A module link allows you to form a relation between two data models of separate modules while maintaining module isolation.
|
|
|
|
<Note title="Tip">
|
|
|
|
Learn more about module links in [this guide](!docs!/learn/fundamentals/module-links).
|
|
|
|
</Note>
|
|
|
|
Create the file `src/links/customer-custom.ts` with the following content:
|
|
|
|
```ts title="src/links/customer-custom.ts"
|
|
import { defineLink } from "@medusajs/framework/utils"
|
|
import HelloModule from "../modules/hello"
|
|
import CustomerModule from "@medusajs/medusa/customer"
|
|
|
|
export default defineLink(
|
|
CustomerModule.linkable.customer,
|
|
HelloModule.linkable.custom
|
|
)
|
|
```
|
|
|
|
This defines a link between the `Customer` and `Custom` data models. Using this link, you'll later query data across the modules, and link records of each data model.
|
|
|
|
---
|
|
|
|
## Step 3: Generate and Run Migrations
|
|
|
|
<Prerequisites
|
|
items={[
|
|
{
|
|
text: "Module must be registered in medusa-config.ts",
|
|
link: "!docs!/learn/fundamentals/modules#4-add-module-to-configurations"
|
|
}
|
|
]}
|
|
/>
|
|
|
|
To reflect the `Custom` data model in the database, generate a migration that defines the table to be created for it.
|
|
|
|
Run the following command in your Medusa project's root:
|
|
|
|
```bash
|
|
npx medusa db:generate helloModuleService
|
|
```
|
|
|
|
Where `helloModuleService` is your module's name.
|
|
|
|
Then, run the `db:migrate` command to run the migrations and create a table in the database for the link between the `Customer` and `Custom` data models:
|
|
|
|
```bash
|
|
npx medusa db:migrate
|
|
```
|
|
|
|
A table for the link is now created in the database. You can now retrieve and manage the link between records of the data models.
|
|
|
|
---
|
|
|
|
## Step 4: Consume customersCreated Workflow Hook
|
|
|
|
When a customer is created, you also want to create a `Custom` record and set the `custom_name` property, then create a link between the `Customer` and `Custom` records.
|
|
|
|
To do that, you'll consume the [customersCreated](/references/medusa-workflows/createCustomersWorkflow#customerscreated) hook of the [createCustomersWorkflow](/references/medusa-workflows/createCustomersWorkflow). This workflow is executed in the [Create Customer Admin API route](!api!/admin#customers_postcustomers)
|
|
|
|
<Note title="Tip">
|
|
|
|
Learn more about workflow hooks in [this guide](!docs!/learn/fundamentals/workflows/workflow-hooks).
|
|
|
|
</Note>
|
|
|
|
The API route accepts in its request body an `additional_data` parameter. You can pass in it custom data, which is passed to the workflow hook handler.
|
|
|
|
### Add custom_name to Additional Data Validation
|
|
|
|
To pass the `custom_name` in the `additional_data` parameter, you must add a validation rule that tells the Medusa application about this custom property.
|
|
|
|
Create the file `src/api/middlewares.ts` with the following content:
|
|
|
|
```ts title="src/api/middlewares.ts"
|
|
import { defineMiddlewares } from "@medusajs/framework/http"
|
|
import { z } from "zod"
|
|
|
|
export default defineMiddlewares({
|
|
routes: [
|
|
{
|
|
method: "POST",
|
|
matcher: "/admin/customers",
|
|
additionalDataValidator: {
|
|
custom_name: z.string().optional(),
|
|
},
|
|
},
|
|
],
|
|
})
|
|
```
|
|
|
|
The `additional_data` parameter validation is customized using `defineMiddlewares`. In the routes middleware configuration object, the `additionalDataValidator` property accepts [Zod](https://zod.dev/) validaiton rules.
|
|
|
|
In the snippet above, you add a validation rule indicating that `custom_name` is a string that can be passed in the `additional_data` object.
|
|
|
|
<Note title="Tip">
|
|
|
|
Learn more about additional data validation in [this guide](!docs!/learn/fundamentals/api-routes/additional-data).
|
|
|
|
</Note>
|
|
|
|
### Create Workflow to Create Custom Record
|
|
|
|
You'll now create a workflow that will be used in the hook handler.
|
|
|
|
This workflow will create a `Custom` record, then link it to the customer.
|
|
|
|
Start by creating the step that creates the `Custom` record. Create the file `src/workflows/create-custom-from-customer/steps/create-custom.ts` with the following content:
|
|
|
|
```ts title="src/workflows/create-custom-from-customer/steps/create-custom.ts"
|
|
import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk"
|
|
import HelloModuleService from "../../../modules/hello/service"
|
|
import { HELLO_MODULE } from "../../../modules/hello"
|
|
|
|
type CreateCustomStepInput = {
|
|
custom_name?: string
|
|
}
|
|
|
|
export const createCustomStep = createStep(
|
|
"create-custom",
|
|
async (data: CreateCustomStepInput, { container }) => {
|
|
if (!data.custom_name) {
|
|
return
|
|
}
|
|
|
|
const helloModuleService: HelloModuleService = container.resolve(
|
|
HELLO_MODULE
|
|
)
|
|
|
|
const custom = await helloModuleService.createCustoms(data)
|
|
|
|
return new StepResponse(custom, custom)
|
|
},
|
|
async (custom, { container }) => {
|
|
const helloModuleService: HelloModuleService = container.resolve(
|
|
HELLO_MODULE
|
|
)
|
|
|
|
await helloModuleService.deleteCustoms(custom.id)
|
|
}
|
|
)
|
|
```
|
|
|
|
In the step, you resolve the Hello Module's main service and create a `Custom` record.
|
|
|
|
In the compensation function that undoes the step's actions in case of an error, you delete the created record.
|
|
|
|
<Note title="Tip">
|
|
|
|
Learn more about compensation functions in [this guide](!docs!/learn/fundamentals/workflows/compensation-function).
|
|
|
|
</Note>
|
|
|
|
Then, create the workflow at `src/workflows/create-custom-from-customer/index.ts` with the following content:
|
|
|
|
```ts title="src/workflows/create-custom-from-customer/index.ts" collapsibleLines="1-7" expandButtonLabel="Show Imports"
|
|
import { createWorkflow, transform, when, WorkflowResponse } from "@medusajs/framework/workflows-sdk"
|
|
import { CustomerDTO } from "@medusajs/framework/types"
|
|
import { createRemoteLinkStep } from "@medusajs/medusa/core-flows"
|
|
import { Modules } from "@medusajs/framework/utils"
|
|
import { HELLO_MODULE } from "../../modules/hello"
|
|
import { createCustomStep } from "./steps/create-custom"
|
|
|
|
export type CreateCustomFromCustomerWorkflowInput = {
|
|
customer: CustomerDTO
|
|
additional_data?: {
|
|
custom_name?: string
|
|
}
|
|
}
|
|
|
|
export const createCustomFromCustomerWorkflow = createWorkflow(
|
|
"create-custom-from-customer",
|
|
(input: CreateCustomFromCustomerWorkflowInput) => {
|
|
const customName = transform(
|
|
{
|
|
input,
|
|
},
|
|
(data) => data.input.additional_data.custom_name || ""
|
|
)
|
|
|
|
const custom = createCustomStep({
|
|
custom_name: customName,
|
|
})
|
|
|
|
when(({ custom }), ({ custom }) => custom !== undefined)
|
|
.then(() => {
|
|
createRemoteLinkStep([{
|
|
[Modules.CUSTOMER]: {
|
|
customer_id: input.customer.id,
|
|
},
|
|
[HELLO_MODULE]: {
|
|
custom_id: custom.id,
|
|
},
|
|
}])
|
|
})
|
|
|
|
return new WorkflowResponse({
|
|
custom,
|
|
})
|
|
}
|
|
)
|
|
```
|
|
|
|
The workflow accepts as an input the created customer and the `additional_data` parameter passed in the request. This is the same input that the `customersCreated` hook accepts.
|
|
|
|
In the workflow, you:
|
|
|
|
1. Use `transform` to get the value of `custom_name` based on whether it's set in `additional_data`. Learn more about why you can't use conditional operators in a workflow without using `transform` in [this guide](!docs!/learn/fundamentals/workflows/conditions#why-if-conditions-arent-allowed-in-workflows).
|
|
2. Create the `Custom` record using the `createCustomStep`.
|
|
3. Use `when-then` to link the customer to the `Custom` record if it was created. Learn more about why you can't use if-then conditions in a workflow without using `when-then` in [this guide](!docs!/learn/fundamentals/workflows/conditions#why-if-conditions-arent-allowed-in-workflows).
|
|
|
|
You'll next execute the workflow in the hook handler.
|
|
|
|
### Consume Workflow Hook
|
|
|
|
You can now consume the `customersCreated` hook, which is executed in the `createCustomersWorkflow` after the customer is created.
|
|
|
|
To consume the hook, create the file `src/workflow/hooks/user-created.ts` with the following content:
|
|
|
|
```ts title="src/workflow/hooks/user-created.ts" collapsibleLines="1-6" expandButtonLabel="Show Imports"
|
|
import { createCustomersWorkflow } from "@medusajs/medusa/core-flows"
|
|
import {
|
|
createCustomFromCustomerWorkflow,
|
|
CreateCustomFromCustomerWorkflowInput,
|
|
} from "../create-custom-from-customer"
|
|
|
|
createCustomersWorkflow.hooks.customersCreated(
|
|
async ({ customers, additional_data }, { container }) => {
|
|
const workflow = createCustomFromCustomerWorkflow(container)
|
|
|
|
for (const customer of customers) {
|
|
await workflow.run({
|
|
input: {
|
|
customer,
|
|
additional_data,
|
|
} as CreateCustomFromCustomerWorkflowInput,
|
|
})
|
|
}
|
|
}
|
|
)
|
|
```
|
|
|
|
The hook handler executes the `createCustomFromCustomerWorkflow`, passing it its input.
|
|
|
|
### Test it Out
|
|
|
|
To test it out, send a `POST` request to `/admin/customers` to create a customer, passing `custom_name` in `additional_data`:
|
|
|
|
```bash
|
|
curl -X POST 'localhost:9000/admin/customers' \
|
|
-H 'Content-Type: application/json' \
|
|
-H 'Authorization: Bearer {token}' \
|
|
--data-raw '{
|
|
"email": "customer@gmail.com",
|
|
"additional_data": {
|
|
"custom_name": "test"
|
|
}
|
|
}'
|
|
```
|
|
|
|
Make sure to replace `{token}` with an admin user's JWT token. Learn how to retrieve it in the [API reference](!api!/admin#1-bearer-authorization-with-jwt-tokens).
|
|
|
|
The request will return the customer's details. You'll learn how to retrieve the `custom_name` property with the customer's details in the next section.
|
|
|
|
---
|
|
|
|
## Step 5: Retrieve custom_name with Customer Details
|
|
|
|
When you extend an existing data model through links, you also want to retrieve the custom properties with the data model.
|
|
|
|
### Retrieve in API Routes using Query
|
|
|
|
You can also retrieve the `Custom` record linked to a customer in your code using [Query](!docs!/learn/fundamentals/module-links/query).
|
|
|
|
For example:
|
|
|
|
```ts
|
|
const { data: [customer] } = await query.graph({
|
|
entity: "customer",
|
|
fields: ["*", "custom.*"],
|
|
filters: {
|
|
id: customer_id,
|
|
},
|
|
})
|
|
```
|
|
|
|
You can use Query in a custom route to retrieve the customer with its linked `Custom` record.
|
|
|
|
Learn more about how to use Query in [this guide](!docs!/learn/fundamentals/module-links/query).
|
|
|
|
---
|
|
|
|
## Step 6: Consume customersUpdated Workflow Hook
|
|
|
|
Similar to the `customersCreated` hook, you'll consume the [customersUpdated](/references/medusa-workflows/updateCustomersWorkflow#customersUpdated) hook of the [updateCustomersWorkflow](/references/medusa-workflows/updateCustomersWorkflow) to update `custom_name` when the customer is updated.
|
|
|
|
The `updateCustomersWorkflow` is executed by the [Update Customer API route](!api!/admin#customers_postcustomersid), which accepts the `additional_data` parameter to pass custom data to the hook.
|
|
|
|
### Add custom_name to Additional Data Validation
|
|
|
|
To allow passing `custom_name` in the `additional_data` parameter of the update customer route, add in `src/api/middlewares.ts` a new route middleware configuration object:
|
|
|
|
```ts title="src/api/middlewares.ts"
|
|
import { defineMiddlewares } from "@medusajs/framework/http"
|
|
import { z } from "zod"
|
|
|
|
export default defineMiddlewares({
|
|
routes: [
|
|
// ...
|
|
{
|
|
method: "POST",
|
|
matcher: "/admin/customers/:id",
|
|
additionalDataValidator: {
|
|
custom_name: z.string().nullish(),
|
|
},
|
|
},
|
|
],
|
|
})
|
|
```
|
|
|
|
The validation schema is the similar to that of the Create Customer API route, except you can pass a `null` value for `custom_name` to remove or unset the `custom_name`'s value.
|
|
|
|
### Create Workflow to Update Custom Record
|
|
|
|
Next, you'll create a workflow that creates, updates, or deletes `Custom` records based on the provided `additional_data` parameter:
|
|
|
|
1. If `additional_data.custom_name` is set and it's `null`, the `Custom` record linked to the customer is deleted.
|
|
2. If `additional_data.custom_name` is set and the customer doesn't have a linked `Custom` record, a new record is created and linked to the customer.
|
|
3. If `additional_data.custom_name` is set and the customer has a linked `Custom` record, the `custom_name` property of the `Custom` record is updated.
|
|
|
|
Start by creating the step that updates a `Custom` record. Create the file `src/workflows/update-custom-from-customer/steps/update-custom.ts` with the following content:
|
|
|
|
```ts title="src/workflows/update-custom-from-customer/steps/update-custom.ts"
|
|
import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk"
|
|
import { HELLO_MODULE } from "../../../modules/hello"
|
|
import HelloModuleService from "../../../modules/hello/service"
|
|
|
|
type UpdateCustomStepInput = {
|
|
id: string
|
|
custom_name: string
|
|
}
|
|
|
|
export const updateCustomStep = createStep(
|
|
"update-custom",
|
|
async ({ id, custom_name }: UpdateCustomStepInput, { container }) => {
|
|
const helloModuleService: HelloModuleService = container.resolve(
|
|
HELLO_MODULE
|
|
)
|
|
|
|
const prevData = await helloModuleService.retrieveCustom(id)
|
|
|
|
const custom = await helloModuleService.updateCustoms({
|
|
id,
|
|
custom_name,
|
|
})
|
|
|
|
return new StepResponse(custom, prevData)
|
|
},
|
|
async (prevData, { container }) => {
|
|
const helloModuleService: HelloModuleService = container.resolve(
|
|
HELLO_MODULE
|
|
)
|
|
|
|
await helloModuleService.updateCustoms(prevData)
|
|
}
|
|
)
|
|
```
|
|
|
|
In this step, you update a `Custom` record. In the compensation function, you revert the update.
|
|
|
|
Next, you'll create the step that deletes a `Custom` record. Create the file `src/workflows/update-custom-from-customer/steps/delete-custom.ts` with the following content:
|
|
|
|
```ts title="src/workflows/update-custom-from-customer/steps/delete-custom.ts" collapsibleLines="1-6" expandButtonLabel="Show Imports"
|
|
import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk"
|
|
import { Custom } from "../../../modules/hello/models/custom"
|
|
import { InferTypeOf } from "@medusajs/framework/types"
|
|
import HelloModuleService from "../../../modules/hello/service"
|
|
import { HELLO_MODULE } from "../../../modules/hello"
|
|
|
|
type DeleteCustomStepInput = {
|
|
custom: InferTypeOf<typeof Custom>
|
|
}
|
|
|
|
export const deleteCustomStep = createStep(
|
|
"delete-custom",
|
|
async ({ custom }: DeleteCustomStepInput, { container }) => {
|
|
const helloModuleService: HelloModuleService = container.resolve(
|
|
HELLO_MODULE
|
|
)
|
|
|
|
await helloModuleService.deleteCustoms(custom.id)
|
|
|
|
return new StepResponse(custom, custom)
|
|
},
|
|
async (custom, { container }) => {
|
|
const helloModuleService: HelloModuleService = container.resolve(
|
|
HELLO_MODULE
|
|
)
|
|
|
|
await helloModuleService.createCustoms(custom)
|
|
}
|
|
)
|
|
```
|
|
|
|
In this step, you delete a `Custom` record. In the compensation function, you create it again.
|
|
|
|
Finally, you'll create the workflow. Create the file `src/workflows/update-custom-from-customer/index.ts` with the following content:
|
|
|
|
```ts title="src/workflows/update-custom-from-customer/index.ts" collapsibleLines="1-9" expandButtonLabel="Show Imports"
|
|
import { CustomerDTO } from "@medusajs/framework/types"
|
|
import { createWorkflow, when, WorkflowResponse } from "@medusajs/framework/workflows-sdk"
|
|
import { createRemoteLinkStep, dismissRemoteLinkStep, useQueryGraphStep } from "@medusajs/medusa/core-flows"
|
|
import { createCustomStep } from "../create-custom-from-customer/steps/create-custom"
|
|
import { Modules } from "@medusajs/framework/utils"
|
|
import { HELLO_MODULE } from "../../modules/hello"
|
|
import { deleteCustomStep } from "./steps/delete-custom"
|
|
import { updateCustomStep } from "./steps/update-custom"
|
|
|
|
export type UpdateCustomFromCustomerStepInput = {
|
|
customer: CustomerDTO
|
|
additional_data?: {
|
|
custom_name?: string | null
|
|
}
|
|
}
|
|
|
|
export const updateCustomFromCustomerWorkflow = createWorkflow(
|
|
"update-custom-from-customer",
|
|
(input: UpdateCustomFromCustomerStepInput) => {
|
|
const { data: customers } = useQueryGraphStep({
|
|
entity: "customer",
|
|
fields: ["custom.*"],
|
|
filters: {
|
|
id: input.customer.id,
|
|
},
|
|
})
|
|
|
|
// TODO create, update, or delete Custom record
|
|
}
|
|
)
|
|
```
|
|
|
|
The workflow accepts the same input as the `customersUpdated` workflow hook handler would.
|
|
|
|
In the workflow, you retrieve the customer's linked `Custom` record using Query.
|
|
|
|
Next, replace the `TODO` with the following:
|
|
|
|
```ts title="src/workflows/update-custom-from-customer/index.ts"
|
|
const created = when(
|
|
"create-customer-custom-link",
|
|
{
|
|
input,
|
|
customers,
|
|
}, (data) =>
|
|
!data.customers[0].custom &&
|
|
data.input.additional_data?.custom_name?.length > 0
|
|
)
|
|
.then(() => {
|
|
const custom = createCustomStep({
|
|
custom_name: input.additional_data.custom_name,
|
|
})
|
|
|
|
createRemoteLinkStep([{
|
|
[Modules.CUSTOMER]: {
|
|
customer_id: input.customer.id,
|
|
},
|
|
[HELLO_MODULE]: {
|
|
custom_id: custom.id,
|
|
},
|
|
}])
|
|
|
|
return custom
|
|
})
|
|
|
|
// TODO update, or delete Custom record
|
|
```
|
|
|
|
Using `when-then`, you check if the customer doesn't have a linked `Custom` record and the `custom_name` property is set. If so, you create a `Custom` record and link it to the customer.
|
|
|
|
To create the `Custom` record, you use the `createCustomStep` you created in an earlier section.
|
|
|
|
Next, replace the new `TODO` with the following:
|
|
|
|
```ts title="src/workflows/update-custom-from-customer/index.ts"
|
|
const deleted = when(
|
|
"delete-customer-custom-link",
|
|
{
|
|
input,
|
|
customers,
|
|
}, (data) =>
|
|
data.customers[0].custom && (
|
|
data.input.additional_data?.custom_name === null ||
|
|
data.input.additional_data?.custom_name.length === 0
|
|
)
|
|
)
|
|
.then(() => {
|
|
deleteCustomStep({
|
|
custom: customers[0].custom,
|
|
})
|
|
|
|
dismissRemoteLinkStep({
|
|
[HELLO_MODULE]: {
|
|
custom_id: customers[0].custom.id,
|
|
},
|
|
})
|
|
|
|
return customers[0].custom.id
|
|
})
|
|
|
|
// TODO delete Custom record
|
|
```
|
|
|
|
Using `when-then`, you check if the customer has a linked `Custom` record and `custom_name` is `null` or an empty string. If so, you delete the linked `Custom` record and dismiss its links.
|
|
|
|
Finally, replace the new `TODO` with the following:
|
|
|
|
```ts title="src/workflows/update-custom-from-customer/index.ts"
|
|
const updated = when({
|
|
input,
|
|
customers,
|
|
}, (data) => data.customers[0].custom && data.input.additional_data?.custom_name?.length > 0)
|
|
.then(() => {
|
|
return updateCustomStep({
|
|
id: customers[0].custom.id,
|
|
custom_name: input.additional_data.custom_name,
|
|
})
|
|
})
|
|
|
|
return new WorkflowResponse({
|
|
created,
|
|
updated,
|
|
deleted,
|
|
})
|
|
```
|
|
|
|
Using `when-then`, you check if the customer has a linked `Custom` record and `custom_name` is passed in the `additional_data`. If so, you update the linked `Custom` record.
|
|
|
|
You return in the workflow response the created, updated, and deleted `Custom` record.
|
|
|
|
### Consume customersUpdated Workflow Hook
|
|
|
|
You can now consume the `customersUpdated` and execute the workflow you created.
|
|
|
|
Create the file `src/workflows/hooks/customer-updated.ts` with the following content:
|
|
|
|
```ts title="src/workflows/hooks/customer-updated.ts"
|
|
import { updateCustomersWorkflow } from "@medusajs/medusa/core-flows"
|
|
import {
|
|
UpdateCustomFromCustomerStepInput,
|
|
updateCustomFromCustomerWorkflow,
|
|
} from "../update-custom-from-customer"
|
|
|
|
updateCustomersWorkflow.hooks.customersUpdated(
|
|
async ({ customers, additional_data }, { container }) => {
|
|
const workflow = updateCustomFromCustomerWorkflow(container)
|
|
|
|
for (const customer of customers) {
|
|
await workflow.run({
|
|
input: {
|
|
customer,
|
|
additional_data,
|
|
} as UpdateCustomFromCustomerStepInput,
|
|
})
|
|
}
|
|
}
|
|
)
|
|
```
|
|
|
|
In the workflow hook handler, you execute the workflow, passing it the hook's input.
|
|
|
|
### Test it Out
|
|
|
|
To test it out, send a `POST` request to `/admin/customers/:id` to update a customer, passing `custom_name` in `additional_data`:
|
|
|
|
```bash
|
|
curl -X POST 'localhost:9000/admin/customers/{customer_id}' \
|
|
-H 'Content-Type: application/json' \
|
|
-H 'Authorization: Bearer {token}' \
|
|
--data '{
|
|
"additional_data": {
|
|
"custom_name": "test3"
|
|
}
|
|
}'
|
|
```
|
|
|
|
Make sure to replace `{customer_id}` with the customer's ID, and `{token}` with the JWT token of an admin user.
|
|
|
|
The request will return the customer's details with the updated `custom` linked record.
|