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:

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