Skip to content

Commit

Permalink
docs: improve workflow hook guides
Browse files Browse the repository at this point in the history
  • Loading branch information
shahednasser committed Aug 9, 2024
1 parent a54ed8b commit 49e0e5e
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 64 deletions.
Original file line number Diff line number Diff line change
@@ -1,31 +1,23 @@
export const metadata = {
title: `${pageNumber} Workflow Hooks`,
title: `${pageNumber} Expose a Workflow Hook`,
}

# {metadata.title}

In this chapter, you'll learn what a workflow hook is, how to expose it in your workflow, and how to consume the hook with a handler.
In this chapter, you'll learn how to expose a hook in your workflow.

## What is a Workflow Hook?

A workflow hook is a point in a workflow where you can inject custom functionality as a step function, called a hook handler.

Hook handlers receive input from the workflow to perform custom actions during the workflow's execution.

<Note title="Use workflow hooks when" type="success">
<Note title="Expose workflow hooks when" type="success">

- Your workflow is reusable in other applications, and you allow performing an external action at some point in your workflow.

</Note>

<Note title="Don't use workflow hooks if" type="error">
<Note title="Don't expose workflow hooks if" type="error">

- Your workflow isn't reusable by other applications. Use a step that performs what a hook handler would instead.

</Note>

---

## How to Expose a Hook in a Workflow?

To expose a hook in your workflow, use the `createHook` function imported from `@medusajs/workflows-sdk`.
Expand Down Expand Up @@ -71,15 +63,9 @@ The `createHook` function accepts two parameters:

The workflow must also pass an object having a `hooks` property as a second parameter to the `WorkflowResponse` constructor. Its value is an array of the workflow's hooks.

---

## How to Consume a Hook?

You consume a hook by registering a hook handler on the workflow. A hook handler is registered in a TypeScript or JavaScript file created in the `src/workflows/hooks` directory.
### How to Consume the Hook?

You'll find a workflow's exposed hooks in its `hooks` property.

For example, to consume the hook of the workflow in the previous example, create the file `src/workflows/hooks/my-workflow.ts` with the following content:
To consume the hook of the workflow, create the file `src/workflows/hooks/my-workflow.ts` with the following content:

export const handlerHighlights = [
["3", "productCreated", "Invoke the hook, passing it a step function as a parameter."],
Expand All @@ -95,31 +81,4 @@ myWorkflow.hooks.productCreated(
)
```

<Note>

A hook can have only one handler.

</Note>

The hook is available on the workflow's `hooks` property using its name `productCreated`. You invoke the hook, passing the handler as a parameter, which is a step function.

Similar to a step, the handler receives the hook's input as a first parameter, and the container in the object as a second parameter.

### Hook Handler Compensation

You can also pass a compensation function as a second parameter:

```ts
import { myWorkflow } from "../my-workflow"

myWorkflow.hooks.productCreated(
async ({ productId }, { container }) => {
// TODO perform an action
},
async () => {
// undo the performed action
}
)
```

The compensation function is executed if an error occurs in the workflow to undo the actions performed by the hook handler.
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,11 @@ In this chapter, you'll learn what a workflow hook is, and an example of how to

A workflow hook is a point in a workflow where you can inject custom functionality as a step function, called a hook handler.

Hook handlers receive input from the workflow to perform custom actions during the workflow's execution.
Medusa exposes hooks in many of its workflows that are used in its API routes. You can consume those hooks to add your custom logic.

<Note title="Use workflow hooks when" type="success">
<Note title="Consume workflow hooks when" type="success">

- Your workflow is reusable in other applications, and you allow performing an external action at some point in your workflow.

</Note>

<Note title="Don't use workflow hooks if" type="error">

- Your workflow isn't reusable by other applications. Use a step that performs what a hook handler would instead.
- You want to perform a custom action during a workflow's execution, such as when a product is created.

</Note>

Expand All @@ -32,30 +26,32 @@ You consume a hook by registering a hook handler on the workflow. A hook handler

You'll find a workflow's exposed hooks in its `hooks` property.

For example, to consume the `productsCreated` hook of the `createProductsWorkflow`, which Medusa uses when a product is created using the admin API routes, create the file `src/workflows/hooks/my-workflow.ts` with the following content:
For example, to consume the `productsCreated` hook of Medusa's `createProductsWorkflow`, create the file `src/workflows/hooks/my-workflow.ts` with the following content:

export const handlerHighlights = [
["3", "productCreated", "Invoke the hook, passing it a step function as a parameter."],
["3", "productsCreated", "Invoke the hook, passing it a step function as a parameter."],
]

```ts title="src/workflows/hooks/my-workflow.ts" highlights={handlerHighlights}
import { myWorkflow } from "../my-workflow"
import { createProductsWorkflow } from "@medusajs/core-flows"

myWorkflow.hooks.productCreated(
async ({ productId }, { container }) => {
createProductsWorkflow.hooks.productsCreated(
async ({ products }, { container }) => {
// TODO perform an action
}
)
```

The hook is available on the workflow's `hooks` property using its name `productsCreated`. You invoke the hook, passing the handler as a parameter, which is a step function.

Now, when a product is created using the Create Product API route, your hooks handler is executed.

<Note>

A hook can have only one handler.

</Note>

The hook is available on the workflow's `hooks` property using its name `productCreated`. You invoke the hook, passing the handler as a parameter, which is a step function.

Similar to a step, the handler receives the hook's input as a first parameter, and the container in the object as a second parameter.

### Hook Handler Compensation
Expand All @@ -76,3 +72,45 @@ myWorkflow.hooks.productCreated(
```

The compensation function is executed if an error occurs in the workflow to undo the actions performed by the hook handler.

### Additional Data

Medusa's workflow hooks pass to their handlers in the first parameter object an `additional_data` property:

```ts highlights={[["4", "additional_data"]]}
import { createProductsWorkflow } from "@medusajs/core-flows"

createProductsWorkflow.hooks.productsCreated(
async ({ products, additional_data }, { container }) => {
// TODO perform an action
}
)
```

This property is an object that holds additional data passed to the workflow.

{/* TODO change to talk about validators once we can document them. */}

To pass that additional data when executing the workflow, pass it as a parameter to the `.run` method of the workflow:

```ts highlights={[["10", "additional_data"]]}
import type { MedusaRequest, MedusaResponse } from "@medusajs/medusa";
import { createProductsWorkflow } from "@medusajs/core-flows"

export async function POST(req: MedusaRequest, res: MedusaResponse) {
await createProductsWorkflow(req.scope).run({
input: {
products: [
// ...
],
additional_data: {
custom_field: "test"
}
},
})
}
```

Your hook handler then receives that passed data in the `additional_data` object.

{/* TODO add a link to the workflows reference once available */}
6 changes: 5 additions & 1 deletion www/apps/book/sidebar.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -212,9 +212,13 @@ export const sidebar = sidebarAttachHrefCommonOptions(
title: "Compensation Function",
},
{
path: "/advanced-development/workflows/add-workflow-hook",
path: "/advanced-development/workflows/workflow-hooks",
title: "Workflow Hooks",
},
{
path: "/advanced-development/workflows/add-workflow-hook",
title: "Expose a Hook",
},
{
path: "/advanced-development/workflows/access-workflow-errors",
title: "Access Workflow Errors",
Expand Down

0 comments on commit 49e0e5e

Please sign in to comment.