docs: add routing page (#9550)

- Add a new homepage to `book` project for the routing page
- Move all main doc pages to be under `/v2/learn` (and added redirects + fixed links across docs)
- Other: add admin components to resources dropdown + fixes to search on mobile.

Closes DX-955

Preview: https://docs-v2-git-docs-router-page-medusajs.vercel.app/v2
This commit is contained in:
Shahed Nasser
2024-10-18 08:24:34 +00:00
committed by GitHub
parent 7a47f5211d
commit 0a37675f0e
223 changed files with 2549 additions and 696 deletions
@@ -0,0 +1,270 @@
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.