Files
medusa-store/www/apps/book/app/basics/workflows/page.mdx
Vraj Patel 7dbef9bedd fix(docs): update workflow API example to include query parameter (#9640)
### Fix Missing Query Parameter in Documentation Example

#### Summary
This pull request addresses a missing query parameter in the Medusa documentation's example for making a request to the workflow endpoint.

#### Issue
The example in the documentation incorrectly shows:
```
curl http://localhost:9000/workflow
```
This causes an issue when running the workflow in code, specifically in `step-2`, where the `name` parameter is `undefined`. 

#### Expected Behavior
The correct curl command should include the `name` query parameter, like so:
```
curl http://localhost:9000/workflow?name=john
```

#### Code Example
Here is the code that demonstrates the issue:

```ts
const step2 = createStep("step-2", async ({ name }: WorkflowInput) => {
  return new StepResponse(`Hello ${name} from step two!`)
})
```

When running the incorrect curl command, the output for `step-2` returns:
```
"Hello undefined from step two!"
```

#### Fix
The pull request proposes updating the example curl command in the documentation to:
```
curl http://localhost:9000/workflow?name=john
```

This ensures that the `name` parameter is correctly passed and resolves the issue of `undefined` values in `step-2`.

#### Steps to Reproduce
1. Implement the workflow and API code as described in the [documentation](https://docs.medusajs.com/v2/basics/workflows#4-test-workflow).
2. Run the curl command:
   ```
   curl http://localhost:9000/workflow
   ```
3. The console will output `Hello undefined from step two!` due to the missing `name` parameter.

#### Suggested Resolution
Update the curl command in the [documentation](https://docs.medusajs.com/v2/basics/workflows#4-test-workflow) to:
```
curl http://localhost:9000/workflow?name=john
```

### Related Issue
Link to the issue: [Medusa Issue #9628](https://github.com/medusajs/medusa/issues/9628)

Co-authored-by: Carlos R. L. Rodrigues <37986729+carlos-r-l-rodrigues@users.noreply.github.com>
2024-10-17 14:51:43 +00:00

271 lines
7.1 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { CodeTabs, CodeTab } from "docs-ui"
export const metadata = {
title: `${pageNumber} Workflows`,
}
# {metadata.title}
In this chapter, youll learn about workflows and how to define and execute them.
## What is a Workflow?
A workflow is a series of queries and actions that complete a task.
You construct a workflow similar to how you create a JavaScript function, but unlike regular functions, a workflow creates an internal representation of your steps.
By using a workflow, you can track its execution's progress, provide roll-back logic for each step to mitigate data inconsistency when errors occur, automatically retry failing steps, and do much more, as explained in later chapters.
---
## How to Create and Execute a Workflow?
### 1. Create the Steps
A workflow is made of a series of steps. A step is created using the `createStep` utility function imported from `@medusajs/framework/workflows-sdk`.
Create the file `src/workflows/hello-world.ts` with the following content:
```ts title="src/workflows/hello-world.ts"
import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk"
const step1 = createStep("step-1", async () => {
return new StepResponse(`Hello from step one!`)
})
```
This creates one step that returns a hello message.
Steps can accept input parameters.
For example, add the following to `src/workflows/hello-world.ts`:
```ts title="src/workflows/hello-world.ts"
type WorkflowInput = {
name: string
}
const step2 = createStep("step-2", async ({ name }: WorkflowInput) => {
return new StepResponse(`Hello ${name} from step two!`)
})
```
### 2. Create a Workflow
Next, add the following to the same file to create the workflow using the `createWorkflow` function:
```ts title="src/workflows/hello-world.ts"
import {
// other imports...
createWorkflow,
WorkflowResponse,
} from "@medusajs/framework/workflows-sdk"
// ...
const myWorkflow = createWorkflow(
"hello-world",
function (input: WorkflowInput) {
const str1 = step1()
// to pass input
const str2 = step2(input)
return new WorkflowResponse({
message: str1,
})
}
)
export default myWorkflow
```
This creates a `hello-world` workflow. When you create a workflow, its constructed but not executed yet.
The workflow must return an instance of `WorkflowResponse`, whose first parameter is returned to workflow executors.
### 3. Execute the Workflow
You can execute a workflow from different resources within Medusa.
- Use API routes to execute the workflow in response to an API request or a webhook.
- Use subscribers to execute a workflow when an event is triggered.
- Use scheduled jobs to execute a workflow on a regular schedule.
To execute the workflow, invoke it passing the Medusa container as a parameter. Then, use its `run` method:
<CodeTabs group="resource-types">
<CodeTab label="API Route" value="api-route">
```ts title="src/api/workflow/route.ts" highlights={[["11"], ["12"], ["13"], ["14"], ["15"], ["16"]]} collapsibleLines="1-6" expandButtonLabel="Show Imports"
import type {
MedusaRequest,
MedusaResponse,
} from "@medusajs/framework/http"
import myWorkflow from "../../workflows/hello-world"
export async function GET(
req: MedusaRequest,
res: MedusaResponse
) {
const { result } = await myWorkflow(req.scope)
.run({
input: {
name: req.query.name as string,
},
})
res.send(result)
}
```
</CodeTab>
<CodeTab label="Subscriber" value="subscriber">
```ts title="src/subscribers/customer-created.ts" highlights={[["20"], ["21"], ["22"], ["23"], ["24"], ["25"]]} collapsibleLines="1-9" expandButtonLabel="Show Imports"
import {
type SubscriberConfig,
type SubscriberArgs,
} from "@medusajs/framework"
import myWorkflow from "../workflows/hello-world"
import { Modules } from "@medusajs/framework/utils"
import { IUserModuleService } from "@medusajs/framework/types"
export default async function handleCustomerCreate({
event: { data },
container,
}: SubscriberArgs<{ id: string }>) {
const userId = data.id
const userModuleService: IUserModuleService = container.resolve(
Modules.USER
)
const user = await userModuleService.retrieveUser(userId)
const { result } = await myWorkflow(container)
.run({
input: {
name: user.first_name,
},
})
console.log(result)
}
export const config: SubscriberConfig = {
event: "user.created",
}
```
</CodeTab>
<CodeTab label="Scheduled Job" value="scheduled-job">
```ts title="src/jobs/message-daily.ts" highlights={[["7"], ["8"], ["9"], ["10"], ["11"], ["12"]]}
import { MedusaContainer } from "@medusajs/framework/types"
import myWorkflow from "../workflows/hello-world"
export default async function myCustomJob(
container: MedusaContainer
) {
const { result } = await myWorkflow(container)
.run({
input: {
name: "John",
},
})
console.log(result.message)
}
export const config = {
name: "run-once-a-day",
schedule: `0 0 * * *`,
};
```
</CodeTab>
</CodeTabs>
### 4. Test Workflow
To test out your workflow, start your Medusa application:
```bash npm2yarn
npm run dev
```
Then, send a `GET` request to `/workflow`:
```bash
curl http://localhost:9000/workflow?name=john
```
Youll receive the following response:
```json
{
"message": "Hello from step one!"
}
```
---
## When to Use Workflows
<Note title="Use workflows when" type="success">
You're implementing a custom feature exposed by an API route, or used in subscribers or scheduled jobs.
</Note>
---
## Resolve Resources
Each step in the workflow receives as a second parameter a `context` object. The object holds a `container` property which is the Medusa container. Use it to resolve other resources, such as services, of your Medusa application.
For example:
export const highlights = [
["12", "resolve", "Resolve the Product Module's main service."],
[
"12",
"Modules.PRODUCT",
"The resource registration name imported from `@medusajs/framework/utils`.",
],
]
```ts title="src/workflows/product-count.ts" highlights={highlights} collapsibleLines="1-9" expandButtonLabel="Show Imports"
import {
createStep,
StepResponse,
createWorkflow,
WorkflowResponse,
} from "@medusajs/framework/workflows-sdk"
import { IProductModuleService } from "@medusajs/framework/types"
import { Modules } from "@medusajs/framework/utils"
const step1 = createStep("step-1", async (_, context) => {
const productModuleService: IProductModuleService =
context.container.resolve(Modules.PRODUCT)
const [, count] = await productModuleService.listAndCountProducts()
return new StepResponse(count)
})
const myWorkflow = createWorkflow(
"product-count",
function () {
const count = step1()
return new WorkflowResponse({
count,
})
}
)
export default myWorkflow
```
In the step, you resolve the Product Module's main service and use it to retrieve the product count.