Skip to content
127 changes: 127 additions & 0 deletions src/content/docs/workflows/build/call-workflows-from-pages.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
---
title: Call Workflows from Pages
pcx_content_type: concept
sidebar:
order: 11
---

import { WranglerConfig, TypeScriptExample } from "~/components";

You can bind and trigger Workflows from [Pages Functions](/pages/functions/) by deploying a Workers project with your Workflow definition and then invoking that Worker using [service bindings](/pages/functions/bindings/#service-bindings) or a standard `fetch()` call.

:::note

You will need to deploy your Workflow as a standalone Workers project first before your Pages Function can call it. Visit the Workflows [get started guide](/workflows/get-started/guide/) if you have not yet deployed a Workflow.

:::

### Use Service Bindings

[Service Bindings](/workers/runtime-apis/bindings/service-bindings/) allow you to call a Worker from another Worker or a Pages Function without needing to expose it directly.

To do this, you:

1. Deploy your Workflow in a Worker
2. Create a Service Binding to that Worker in your Pages project
3. Call the Worker remotely using the binding

For example, if you have a Worker called `workflows-starter`, you would create a new Service Binding in your Pages project as follows, ensuring that the `service` name matches the name of the Worker your Workflow is defined in:

<WranglerConfig>
```toml
services = [
{ binding = "WORKFLOW_SERVICE", service = "workflows-starter" }
]
```
</WranglerConfig>

Your Worker can expose a specific method (or methods) that only other Workers or Pages Functions can call over the Service Binding.

In the following example, we expose a specific `createInstance` method that accepts our `Payload` and returns the [`InstanceStatus`](/workflows/build/workers-api/#instancestatus) from the Workflows API:

<TypeScriptExample filename="index.ts">
import { WorkerEntrypoint } from "cloudflare:workers";

interface Env {
MY_WORKFLOW: Workflow;
}

type Payload = {
hello: string;
}

export default class WorkflowsService extends WorkerEntrypoint<Env> {
// Currently, entrypoints without a named handler are not supported
async fetch() { return new Response(null, {status: 404}); }

async createInstance(payload: Payload) {
let instance = await this.env.MY_WORKFLOW.create({
params: payload
});

return Response.json({
id: instance.id,
details: await instance.status(),
});
}
}
</TypeScriptExample>

Your Pages Function would resemble the followijng:

<TypeScriptExample filename="functions/request.ts">
interface Env {
WORKFLOW_SERVICE: Service;
}

export const onRequest: PagesFunction<Env> = async (context) => {
// This payload could be anything from within your app or from your frontend
let payload = {"hello": "world"}
return context.env.WORKFLOWS_SERVICE.createInstance(payload)
};
</TypeScriptExample>

Visit the [bindings documentation for Pages Functions](/pages/functions/bindings/#service-bindings) to learn more about binding to resources from Pages Functions, including how to bind via the Cloudflare dashboard.

### Using fetch

:::note

We recommend using [Service Bindings](/workers/runtime-apis/bindings/service-bindings/) when calling a Worker in your own account.

Service Bindings don't require you to expose a public endpoint from your Worker, don't require you to configure authentication, and allow you to call methods on your Worker directly, avoiding the overhead of managing HTTP requests and responses.

:::

An alternative to setting up a Service Binding is to call the Worker over HTTP by using the Workflows [Workers API](/workflows/build/workers-api/#workflow) to `create` a new Workflow instance for each incoming HTTP call to the Worker:

<TypeScriptExample filename="index.ts">
// This is in the same file as your Workflow definition
export default {
async fetch(req: Request, env: Env): Promise<Response> {
let instance = await env.MY_WORKFLOW.create({
params: payload
});
return Response.json({
id: instance.id,
details: await instance.status(),
});
},
};
</TypeScriptExample>

Your [Pages Function](/pages/functions/get-started/) can then make a regular `fetch` call to the Worker:

<TypeScriptExample filename="functions/request.ts">
export const onRequest: PagesFunction<Env> = async (context) => {
// Other code
let payload = {"hello": "world"}
const instanceStatus = fetch("https://YOUR_WORKER.workers.dev/", {
method: "POST",
body: JSON.stringify(payload) // Send a paylod for our Worker to pass to the Workflow
}
return Response.json(instanceStatus);
};
</TypeScriptExample>

You can also choose to authenticate these requests by passing a shared secret in a header and validating that in your Worker.
11 changes: 7 additions & 4 deletions src/content/docs/workflows/build/workers-api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -125,17 +125,20 @@ binding = "MY_WORKFLOW"
# this is class that extends the Workflow class in src/index.ts
class_name = "MyWorkflow"
```

</WranglerConfig>

### Bind from Pages

You can bind and trigger Workflows from [Pages Functions](/pages/functions/) by deploying a Workers project with your Workflow definition and then invoking that Worker using [service bindings](/pages/functions/bindings/#service-bindings) or a standard `fetch()` call.

Visit the documentation on [calling Workflows from Pages](/workflows/build/call-workflows-from-pages/) for examples.

### Cross-script calls

You can also bind to a Workflow that is defined in a different Worker script from the script your Workflow definition is in. To do this, provide the `script_name` key with the name of the script to the `[[workflows]]` binding definition in your `wrangler.toml` configuration.

For example, if your Workflow is defined in a Worker script named `billing-worker`, but you are calling it from your `web-api-worker` script, your `wrangler.toml` would resemble the following:



<WranglerConfig>

```toml title="wrangler.toml"
Expand Down Expand Up @@ -228,7 +231,7 @@ export default {
// params expects the type User
params: user
})

return Response.json({
id: instance.id,
details: await instance.status(),
Expand Down
Loading