Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: revise create brand workflow #10346

Merged
merged 3 commits into from
Nov 28, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
docs: revise create brand workflow
  • Loading branch information
shahednasser committed Nov 28, 2024
commit 5a239f51c09bda71236adbd95700344161775d38
Original file line number Diff line number Diff line change
@@ -1,35 +1,23 @@
import { Prerequisites } from "docs-ui"

export const metadata = {
title: `${pageNumber} Define Workflow to Create a Brand`,
title: `${pageNumber} Guide: Create Brand Workflow`,
}

# {metadata.title}

<Note title="Example Chapter">
This chapter is a follow-up to the [previous one](../module/page.mdx) where you created a Brand Module. In this chapter, you'll create a workflow that creates a brand.

This chapter covers how to define a workflow that creates a brand as part of the ["Build Custom Features" chapter](../page.mdx).
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.

</Note>

## Workflows vs Services: Why use Workflows?

When manipulating data, use workflows instead of invoking a service's methods directly in your API route or other customizations.

Workflows eliminate data inconsistency in your application with its compensation mechanism that undoes changes if an error occurs. For example, if a workflow's step creates a brand, it also defines a compensation mechanism to remove the brand if an error occurs.
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](../api-route/page.mdx), 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.

<Note>

Learn more about workflows [in this guide](../../../basics/workflows/page.mdx).
Learn more about workflows in [this chapter](../../../basics/workflows/page.mdx).

</Note>

This is even more useful when you create workflows with many steps, or integrate third-party systems.

---

## Create createBrandWorkflow

<Prerequisites
items={[
{
@@ -39,46 +27,29 @@ This is even more useful when you create workflows with many steps, or integrate
]}
/>

Create the file `src/workflows/create-brand/index.ts` with the following content:

```ts
import {
createWorkflow,
WorkflowResponse,
} from "@medusajs/framework/workflows-sdk"

export type CreateBrandInput = {
name: string
}

export const createBrandWorkflow = createWorkflow(
"create-brand",
(input: CreateBrandInput) => {
// TODO
}
)
```

For now, this workflow only defines its input. You'll create its step and use it in the workflow.

---

## Create createBrandStep
## 1. Create createBrandStep

Create the file `src/workflows/create-brand/steps/create-brand.ts` with the following content:
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`.

```ts title="src/workflows/create-brand/steps/create-brand.ts" collapsibleLines="1-8" expandButtonLabel="Show Imports"
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:

```ts title="src/workflows/create-brand/steps/create-brand.ts"
import {
createStep,
StepResponse,
} from "@medusajs/framework/workflows-sdk"
import { CreateBrandInput } from ".."
import { BRAND_MODULE } from "../../../modules/brand"
import BrandModuleService from "../../../modules/brand/service"

export type CreateBrandStepInput = {
name: string
}

export const createBrandStep = createStep(
"create-brand-step",
async (input: CreateBrandInput, { container }) => {
async (input: CreateBrandStepInput, { container }) => {
const brandModuleService: BrandModuleService = container.resolve(
BRAND_MODULE
)
@@ -90,17 +61,33 @@ export const createBrandStep = createStep(
)
```

This defines a `createBrandStep`. In the step, you resolve the Brand Module's main service and use its generated `createBrands` method, which accepts one or more objects of brands to create.
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 returns the created brand in the first parameter of the `StepResponse`'s constructor.
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](../../../basics/medusa-container/page.mdx) 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.

<Note>

Learn more about the generated `create` method's usage in [this reference](!resources!/service-factory-reference/methods/create).

</Note>

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

A compensation function rolls back changes made by the step if an error occurs in the workflow.
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.

The second parameter of the `StepResponse`'s constructor is passed to the compensation function.
<Note>

Learn more about the compensation function in [this chapter](../../../advanced-development/workflows/compensation-function/page.mdx).

</Note>

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

```ts title="src/workflows/create-brand/steps/create-brand.ts"
export const createBrandStep = createStep(
@@ -115,38 +102,57 @@ export const createBrandStep = createStep(
)
```

You resolve the Brand Module's main service and use its generated `deleteBrands` method to delete the brand created by the step.
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.

<Note title="Tip">
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.

The `deleteBrands` method accepts an ID or an array of IDs of brands to delete.
<Note>

Learn more about the generated `delete` method's usage in [this reference](!resources!/service-factory-reference/methods/delete).

</Note>

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

---

## Add Step to Workflow
## 2. Create createBrandWorkflow

Go back to the workflow at `src/workflows/create-brand/index.ts` and import the step you created:
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:

```ts
import {
createWorkflow,
WorkflowResponse,
} from "@medusajs/framework/workflows-sdk"
import { createBrandStep } from "./steps/create-brand"
```

Then, replace the `TODO` with the following:
type CreateBrandInput = {
name: string
}

```ts
const brand = createBrandStep(input)
export const createBrandWorkflow = createWorkflow(
"create-brand",
(input: CreateBrandInput) => {
const brand = createBrandStep(input)

return new WorkflowResponse(brand)
return new WorkflowResponse(brand)
}
)
```

You use the `createBrandStep` to create the brand and return it in the workflow's response.
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 Step: Create Brand API Route
## Next Steps: Expose Create Brand API Route

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

In the next step, you'll create an API route that allows admin users to create a brand using this workflow.
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.
2 changes: 1 addition & 1 deletion www/apps/book/generated/edit-dates.mjs
Original file line number Diff line number Diff line change
@@ -91,7 +91,7 @@ export const generatedEditDates = {
"app/learn/advanced-development/workflows/variable-manipulation/page.mdx": "2024-11-14T16:11:24.538Z",
"app/learn/customization/custom-features/api-route/page.mdx": "2024-09-12T12:42:34.201Z",
"app/learn/customization/custom-features/module/page.mdx": "2024-10-16T08:49:44.676Z",
"app/learn/customization/custom-features/workflow/page.mdx": "2024-09-30T08:43:53.133Z",
"app/learn/customization/custom-features/workflow/page.mdx": "2024-11-28T10:47:28.084Z",
"app/learn/customization/extend-models/create-links/page.mdx": "2024-09-30T08:43:53.133Z",
"app/learn/customization/extend-models/extend-create-product/page.mdx": "2024-09-30T08:43:53.134Z",
"app/learn/customization/custom-features/page.mdx": "2024-09-12T11:18:13.271Z",
2 changes: 1 addition & 1 deletion www/apps/book/sidebar.mjs
Original file line number Diff line number Diff line change
@@ -103,7 +103,7 @@ export const sidebar = numberSidebarItems(
},
{
type: "link",
title: "Create Brand Workflow",
title: "Brand Workflow",
path: "/learn/customization/custom-features/workflow",
},
{