- Get Started
- Product
- Resources
- Tools & SDKs
- Framework
- Reference
- Get Started
- Product
- Resources
- Tools & SDKs
- Framework
- Reference
3.5.9. Pass Additional Data to Medusa's API Route
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 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#
API Routes List
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:
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 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.
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:
1curl -X POST 'http://localhost:9000/admin/products' \2-H 'Content-Type: application/json' \3-H 'Authorization: Bearer {token}' \4--data '{5 "title": "Product 1",6 "options": [7 {8 "title": "Default option",9 "values": ["Default option value"]10 }11 ],12 "additional_data": {13 "brand": "Acme"14 }15}'
{token}
in the authorization header with an admin user's authentication token.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#
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:
1import { StepResponse } from "@medusajs/framework/workflows-sdk"2import { createProductsWorkflow } from "@medusajs/medusa/core-flows"3import { Modules } from "@medusajs/framework/utils"4 5createProductsWorkflow.hooks.productsCreated(6 async ({ products, additional_data }, { container }) => {7 if (!additional_data?.brand) {8 return9 }10 11 const productModuleService = container.resolve(12 Modules.PRODUCT13 )14 15 await productModuleService.upsertProducts(16 products.map((product) => ({17 ...product,18 metadata: {19 ...product.metadata,20 brand: additional_data.brand,21 },22 }))23 )24 25 return new StepResponse(products, {26 products,27 additional_data,28 })29 }30)
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:
1createProductsWorkflow.hooks.productsCreated(2 async ({ products, additional_data }, { container }) => {3 // ...4 },5 async ({ products, additional_data }, { container }) => {6 if (!additional_data.brand) {7 return8 }9 10 const productModuleService = container.resolve(11 Modules.PRODUCT12 )13 14 await productModuleService.upsertProducts(15 products16 )17 }18)
This updates the products to their original state before adding the brand to their metadata
property.