3.1.2. Guide: Create Brand Workflow

This chapter is a follow-up to the previous one where you created a Brand Module. In this chapter, you'll create a workflow that creates a brand.

You implement commerce features within workflows. A workflow is a series of queries and actions, called steps, that complete a task. You construct a workflow similar to a regular function, but it's a special function that allows you to define roll-back logic, retry configurations, and more advanced features.

The workflow you'll create in this chapter will use the Brand Module's service to implement the feature of creating a brand. In the next chapter, you'll expose an API route that allows admin users to create a brand, and you'll use this workflow in the route's implementation.

NoteLearn more about workflows in this chapter .

1. Create createBrandStep#

A workflow consists of a series of steps, each step created in a TypeScript or JavaScript file under the src/workflows directory. A step is defined using the createStep utility function imported from @medusajs/framework/workflows-sdk.

The workflow you're creating in this guide has one step to create the brand. So, create the file src/workflows/create-brand/steps/create-brand.ts with the following content:

src/workflows/create-brand/steps/create-brand.ts
1import {2  createStep,3  StepResponse,4} from "@medusajs/framework/workflows-sdk"5import { BRAND_MODULE } from "../../../modules/brand"6import BrandModuleService from "../../../modules/brand/service"7
8export type CreateBrandStepInput = {9  name: string10}11
12export const createBrandStep = createStep(13  "create-brand-step",14  async (input: CreateBrandStepInput, { container }) => {15    const brandModuleService: BrandModuleService = container.resolve(16      BRAND_MODULE17    )18
19    const brand = await brandModuleService.createBrands(input)20
21    return new StepResponse(brand, brand.id)22  }23)

You create a createBrandStep using the createStep function. It accepts the step's unique name as a first parameter, and the step's function as a second parameter.

The step function receives two parameters: input passed to the step when it's invoked, and an object of general context and configurations. This object has a container property, which is the Medusa container.

The Medusa container is a registry of framework and commerce tools accessible in your customizations, such as a workflow's step. The Medusa application registers the services of core and custom modules in the container, allowing you to resolve and use them.

So, In the step function, you use the Medusa container to resolve the Brand Module's service and use its generated createBrands method, which accepts an object of brands to create.

NoteLearn more about the generated create method's usage in this reference .

A step must return an instance of StepResponse. Its first parameter is the data returned by the step, and the second is the data passed to the compensation function, which you'll learn about next.

Add Compensation Function to Step#

You define for each step a compensation function that's executed when an error occurs in the workflow. The compensation function defines the logic to roll-back the changes made by the step. This ensures your data remains consistent if an error occurs, which is especially useful when you integrate third-party services.

NoteLearn more about the compensation function in this chapter .

To add a compensation function to the createBrandStep, pass it as a third parameter to createStep:

src/workflows/create-brand/steps/create-brand.ts
1export const createBrandStep = createStep(2  // ...3  async (id: string, { container }) => {4    const brandModuleService: BrandModuleService = container.resolve(5      BRAND_MODULE6    )7
8    await brandModuleService.deleteBrands(id)9  }10)

The compensation function's first parameter is the brand's ID which you passed as a second parameter to the step function's returned StepResponse. It also accepts a context object with a container property as a second parameter, similar to the step function.

In the compensation function, you resolve the Brand Module's service from the Medusa container, then use its generated deleteBrands method to delete the brand created by the step. This method accepts the ID of the brand to delete.

NoteLearn more about the generated delete method's usage in this reference .

So, if an error occurs during the workflow's execution, the brand that was created by the step is deleted to maintain data consistency.


2. Create createBrandWorkflow#

You can now create the workflow that runs the createBrandStep. A workflow is created in a TypeScript or JavaScript file under the src/workflows directory. In the file, you use the createWorkflow function imported from @medusajs/framework/workflows-sdk to create the workflow.

So, create the file src/workflows/create-brand/index.ts with the following content:

Code
1import {2  createWorkflow,3  WorkflowResponse,4} from "@medusajs/framework/workflows-sdk"5import { createBrandStep } from "./steps/create-brand"6
7type CreateBrandInput = {8  name: string9}10
11export const createBrandWorkflow = createWorkflow(12  "create-brand",13  (input: CreateBrandInput) => {14    const brand = createBrandStep(input)15
16    return new WorkflowResponse(brand)17  }18)

You create the createBrandWorkflow using the createWorkflow function. This function accepts two parameters: the workflow's unique name, and the workflow's constructor function holding the workflow's implementation.

The constructor function accepts the workflow's input as a parameter. In the function, you invoke the createBrandStep you created in the previous step to create a brand.

A workflow must return an instance of WorkflowResponse. It accepts as a parameter the data to return to the workflow's executor.


Next Steps: Expose Create Brand API Route#

You now have a createBrandWorkflow that you can execute to create a brand.

In the next chapter, you'll add an API route that allows admin users to create a brand. You'll learn how to create the API route, and execute in it the workflow you implemented in this chapter.

Was this chapter helpful?
Edit this page