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:

src/api/middlewares.ts
1import { defineMiddlewares } from "@medusajs/framework/http"2import { z } from "zod"3
4export default defineMiddlewares({5  routes: [6    {7      method: "POST",8      matcher: "/admin/products",9      additionalDataValidator: {10        brand: z.string().optional(),11      },12    },13  ],14})

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.

NoteRefer to Zod's documentation for all available validation rules.

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:

Code
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}'
TipMake sure to replace the {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#

NoteLearn about workflow hooks in this guide.

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:

src/workflows/hooks/product-created.ts
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:

src/workflows/hooks/product-created.ts
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.

Was this chapter helpful?
Edit this page
Ask Anything
FAQ
What is Medusa?
How can I create a module?
How can I create a data model?
How do I create a workflow?
How can I extend a data model in the Product Module?
Recipes
How do I build a marketplace with Medusa?
How do I build digital products with Medusa?
How do I build subscription-based purchases with Medusa?
What other recipes are available in the Medusa documentation?
Chat is cleared on refresh
Line break