- Get Started
- Product
- Resources
- Tools & SDKs
- Framework
- Reference
- Get Started
- Product
- Resources
- Tools & SDKs
- Framework
- Reference
4.2.3. Extend Create Product API Route
Additional Data in API Routes#
Some API routes, including the Create Product API route, accept an additional_data
request body parameter.
It's useful when you want to pass custom data, such as the brand ID, then perform an action based on this data, such as link the brand to the product.
1. Allow Passing the Brand ID in Additional Data#
Before passing custom properties in the additional_data
parameter, you add the property to additional_data
's validation rules.
Create the file src/api/middlewares.ts
, which is a special file that defines middlewares or validation rules of custom properties passed in the additional_data
parameter:
You use Zod to add a validation rule to the additional_data
parameter indicating that it can include a brand_id
property of type string.
defineMiddleware Parameters#
The defineMiddlewares
function accepts an object having a routes
property. Its value is an array of middleware route objects, each having the following properties:
matcher
: a string or regular expression indicating the API route path to apply the middleware on. It must be compatible with path-to-regexp.method
: An array of HTTP method to apply the middleware or additional data validation to. If not supplied, it's applied to all HTTP methods.additionalDataValidator
: An object of key-value pairs defining the validation rules for custom properties using Zod.
2. Link Brand to Product using Workflow Hook#
A workflow hook is a point in a workflow where you can inject a step to perform a custom functionality. This is useful to perform custom action in an API route's workflow.
The createProductsWorkflow used in the Create Product API route has a productsCreated
hook that runs after the product is created.
So, to consume the productsCreated
hook, create the file src/workflows/hooks/created-product.ts
with the following content:
1import { createProductsWorkflow } from "@medusajs/medusa/core-flows"2import { StepResponse } from "@medusajs/framework/workflows-sdk"3import { Modules, ContainerRegistrationKeys } from "@medusajs/framework/utils"4import { BRAND_MODULE } from "../../modules/brand"5import BrandModuleService from "../../modules/brand/service"6 7createProductsWorkflow.hooks.productsCreated(8 (async ({ products, additional_data }, { container }) => {9 if (!additional_data?.brand_id) {10 return new StepResponse([], [])11 }12 13 // check that brand exists14 const brandModuleService: BrandModuleService = container.resolve(15 BRAND_MODULE16 )17 // if the brand doesn't exist, an error is thrown.18 await brandModuleService.retrieveBrand(additional_data.brand_id as string)19 20 const remoteLink = container.resolve(21 ContainerRegistrationKeys.REMOTE_LINK22 )23 const logger = container.resolve(24 ContainerRegistrationKeys.LOGGER25 )26 27 const links = []28 29 // link products to brands30 for (const product of products) {31 links.push({32 [Modules.PRODUCT]: {33 product_id: product.id,34 },35 [BRAND_MODULE]: {36 brand_id: additional_data.brand_id,37 },38 })39 }40 41 await remoteLink.create(links)42 43 logger.info("Linked brand to products")44 45 return new StepResponse(links, links)46 })47)
Workflows have a special hooks
property to access its hooks and consume them. Each hook, such as productCreated
, accept a step function as a parameter.
In the step, if a brand ID is passed in additional_data
and the brand exists, you create a link between each product and the brand.
Dismiss Links in Compensation#
You can pass as a second parameter of the hook a compensation function that undoes what the step did.
Add the following compensation function as a second parameter:
In the compensation function, you dismiss the links created by the step using the dismiss
method of the remote link.
Test it Out#
To test it out, first, retrieve the authentication token of your admin user by sending a POST
request to /auth/user/emailpass
:
Make sure to replace the email and password with your user's credentials.
Then, send a POST
request to /admin/products
to create a product, and pass in the additional_data
parameter a brand's ID:
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_id": "01J7AX9ES4X113HKY6C681KDZ2J"14 }15}'
In the request body, you pass in the additional_data
parameter a brand_id
.
The request creates a product and returns it.
In the Medusa application's logs, you'll find the message Linked brand to products
, indicating that the workflow hook handler ran and linked the brand to the products.
Workflows and API Routes References#
Medusa exposes hooks in many of its workflows that you can consume to add custom logic.
The Store and Admin API references indicate what workflows are used in each API routes. By clicking on the workflow, you access the workflow's reference where you can see the hooks available in the workflow.
Next Steps: Query Linked Records#
In the next chapter, you'll learn how to query the brand linked to a product.