* docs: update imports and package names across docs + reference configs * generate files * fix import * change preview to rc
202 lines
6.7 KiB
Plaintext
202 lines
6.7 KiB
Plaintext
import { Details } from "docs-ui"
|
|
|
|
export const metadata = {
|
|
title: `${pageNumber} Pass Additional Data to Medusa's API Route`,
|
|
}
|
|
|
|
# {metadata.title}
|
|
|
|
In this chapter, you'll learn how to pass additional data in requests to Medusa's API Route.
|
|
|
|
## Why Pass Additional Data?
|
|
|
|
Some of Medusa's API Routes accept an `additional_data` parameter whose type is an object. The API Route passes the `additional_data` to the workflow, which in turn passes it to its hooks.
|
|
|
|
This is useful when you have a link from your custom module to a commerce module, and you want to perform an additional action when a request is sent to an existing API route.
|
|
|
|
For example, the [Create Product API Route](!api!/admin#products_postproducts) accepts an `additional_data` parameter. If you have a data model linked to it, you consume the `productsCreated` hook to create a record of the data model using the custom data and link it to the product.
|
|
|
|
### API Routes Accepting Additional Data
|
|
|
|
<Details summaryContent="API Routes List">
|
|
|
|
- Campaigns
|
|
- [Create Campaign](!api!/admin#campaigns_postcampaigns)
|
|
- [Update Campaign](!api!/admin#campaigns_postcampaignsid)
|
|
- Cart
|
|
- [Create Cart](!api!/store#carts_postcarts)
|
|
- [Update Cart](!api!/store#carts_postcartsid)
|
|
- Customers
|
|
- [Create Customer](!api!/admin#customers_postcustomers)
|
|
- [Update Customer](!api!/admin#customers_postcustomersid)
|
|
- [Create Address](!api!/admin#customers_postcustomersidaddresses)
|
|
- [Update Address](!api!/admin#customers_postcustomersidaddressesaddress_id)
|
|
- Draft Orders
|
|
- [Create Draft Order](!api!/admin#draft-orders_postdraftorders)
|
|
- Orders
|
|
- [Complete Orders](!api!/admin#orders_postordersidcomplete)
|
|
- [Cancel Order's Fulfillment](!api!/admin#orders_postordersidfulfillmentsfulfillment_idcancel)
|
|
- [Create Shipment](!api!/admin#orders_postordersidfulfillmentsfulfillment_idshipments)
|
|
- [Create Fulfillment](!api!/admin#orders_postordersidfulfillments)
|
|
- Products
|
|
- [Create Product](!api!/admin#products_postproducts)
|
|
- [Update Product](!api!/admin#products_postproductsid)
|
|
- [Create Product Variant](!api!/admin#products_postproductsidvariants)
|
|
- [Update Product Variant](!api!/admin#products_postproductsidvariantsvariant_id)
|
|
- [Create Product Option](!api!/admin#products_postproductsidoptions)
|
|
- [Update Product Option](!api!/admin#products_postproductsidoptionsoption_id)
|
|
- Promotions
|
|
- [Create Promotion](!api!/admin#promotions_postpromotions)
|
|
- [Update Promotion](!api!/admin#promotions_postpromotionsid)
|
|
|
|
</Details>
|
|
|
|
---
|
|
|
|
## How to Pass Additional Data
|
|
|
|
### 1. Specify Validation of Additional Data
|
|
|
|
Before passing custom data in the `additional_data` object parameter, you must specify validation rules for the allowed properties in the object.
|
|
|
|
To do that, use the middleware route object defined in `src/api/middlewares.ts`.
|
|
|
|
For example, create the file `src/api/middlewares.ts` with the following content:
|
|
|
|
```ts title="src/api/middlewares.ts"
|
|
import { defineMiddlewares } from "@medusajs/medusa"
|
|
import { z } from "zod"
|
|
|
|
export default defineMiddlewares({
|
|
routes: [
|
|
{
|
|
method: "POST",
|
|
matcher: "/admin/products",
|
|
additionalDataValidator: {
|
|
brand: z.string().optional(),
|
|
},
|
|
},
|
|
],
|
|
})
|
|
```
|
|
|
|
The middleware route object accepts an optional parameter `additionalDataValidator` whose value is an object of key-value pairs. The keys indicate the name of accepted properties in the `additional_data` parameter, and the value is [Zod](https://zod.dev/) validation rules of the property.
|
|
|
|
In this example, you indicate that the `additional_data` parameter accepts a `brand` property whose value is an optional string.
|
|
|
|
<Note>
|
|
|
|
Refer to [Zod's documentation](https://zod.dev) for all available validation rules.
|
|
|
|
</Note>
|
|
|
|
### 2. Pass the Additional Data in a Request
|
|
|
|
You can now pass a `brand` property in the `additional_data` parameter of a request to the Create Product API Route.
|
|
|
|
For example:
|
|
|
|
```bash
|
|
curl -X POST 'http://localhost:9000/admin/products' \
|
|
-H 'Content-Type: application/json' \
|
|
-H 'Authorization: Bearer {token}' \
|
|
--data '{
|
|
"title": "Product 1",
|
|
"additional_data": {
|
|
"brand": "Acme"
|
|
}
|
|
}'
|
|
```
|
|
|
|
<Note title="Tip">
|
|
|
|
Make sure to replace the `{token}` in the authorization header with an admin user's authentication token.
|
|
|
|
</Note>
|
|
|
|
In this request, you pass in the `additional_data` parameter a `brand` property and set its value to `Acme`.
|
|
|
|
The `additional_data` is then passed to hooks in the `createProductsWorkflow` used by the API route.
|
|
|
|
---
|
|
|
|
## Use Additional Data in a Hook
|
|
|
|
<Note>
|
|
|
|
Learn about workflow hooks in [this guide](../../workflows/workflow-hooks/page.mdx).
|
|
|
|
</Note>
|
|
|
|
Step functions consuming the workflow hook can access the `additional_data` in the first parameter.
|
|
|
|
For example, consider you want to store the data passed in `additional_data` in the product's `metadata` property.
|
|
|
|
To do that, create the file `src/workflows/hooks/product-created.ts` with the following content:
|
|
|
|
```ts title="src/workflows/hooks/product-created.ts"
|
|
import { StepResponse } from "@medusajs/framework/workflows-sdk"
|
|
import { createProductsWorkflow } from "@medusajs/medusa/core-flows"
|
|
import { Modules } from "@medusajs/framework/utils"
|
|
|
|
createProductsWorkflow.hooks.productsCreated(
|
|
async ({ products, additional_data }, { container }) => {
|
|
if (!additional_data.brand) {
|
|
return
|
|
}
|
|
|
|
const productModuleService = container.resolve(
|
|
Modules.PRODUCT
|
|
)
|
|
|
|
await productModuleService.upsertProducts(
|
|
products.map((product) => ({
|
|
...product,
|
|
metadata: {
|
|
...product.metadata,
|
|
brand: additional_data.brand,
|
|
},
|
|
}))
|
|
)
|
|
|
|
return new StepResponse(products, {
|
|
products,
|
|
additional_data,
|
|
})
|
|
}
|
|
)
|
|
```
|
|
|
|
This consumes the `productsCreated` hook, which runs after the products are created.
|
|
|
|
If `brand` is passed in `additional_data`, you resolve the Product Module's main service and use its `upsertProducts` method to update the products, adding the brand to the `metadata` property.
|
|
|
|
### Compensation Function
|
|
|
|
Hooks also accept a compensation function as a second parameter to undo the actions made by the step function.
|
|
|
|
For example, pass the following second parameter to the `productsCreated` hook:
|
|
|
|
```ts title="src/workflows/hooks/product-created.ts"
|
|
createProductsWorkflow.hooks.productsCreated(
|
|
async ({ products, additional_data }, { container }) => {
|
|
// ...
|
|
},
|
|
async ({ products, additional_data }, { container }) => {
|
|
if (!additional_data.brand) {
|
|
return
|
|
}
|
|
|
|
const productModuleService = container.resolve(
|
|
Modules.PRODUCT
|
|
)
|
|
|
|
await productModuleService.upsertProducts(
|
|
products
|
|
)
|
|
}
|
|
)
|
|
```
|
|
|
|
This updates the product to their original state before adding the brand to their `metadata` property.
|