Skip to content
Open
Changes from all commits
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
68 changes: 49 additions & 19 deletions src/content/partials/workers/service-binding-rpc-example.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,36 @@
{}
---

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

The TypeScript example below uses a separate directory for each Worker:

```txt
rpc-example/
├── worker-a/
│ ├── src/index.ts
│ └── wrangler.jsonc
└── worker-b/
├── src/index.ts
└── wrangler.jsonc
```

For example, if Worker B implements the public method `add(a, b)`:
Worker B implements the public method `add(a, b)`:

<WranglerConfig>

```jsonc
{
"$schema": "./node_modules/wrangler/config-schema.json",
"name": "worker_b",
"main": "./src/workerB.js",
"name": "worker-b",
"main": "./src/index.ts",
"compatibility_date": "$today",
"upload_source_maps": true
}
```
Expand All @@ -27,10 +46,6 @@ For example, if Worker B implements the public method `add(a, b)`:
import { WorkerEntrypoint } from "cloudflare:workers";

export default class extends WorkerEntrypoint {
async fetch() {
return new Response("Hello from Worker B");
}

add(a: number, b: number) {
return a + b;
}
Expand All @@ -42,12 +57,9 @@ export default class extends WorkerEntrypoint {
<TabItem label="Python" icon="seti:python">

```python
from workers import WorkerEntrypoint, Response
from workers import WorkerEntrypoint

class Default(WorkerEntrypoint):
async def fetch(self, request):
return Response("Hello from Worker B")

def add(self, a: int, b: int) -> int:
return a + b
```
Expand All @@ -63,34 +75,44 @@ Worker A can declare a [binding](/workers/runtime-apis/bindings) to Worker B:
```jsonc
{
"$schema": "./node_modules/wrangler/config-schema.json",
"name": "worker_a",
"main": "./src/workerA.js",
"name": "worker-a",
"main": "./src/index.ts",
"compatibility_date": "$today",
"upload_source_maps": true,
"services": [
{
"binding": "WORKER_B",
"service": "worker_b"
"service": "worker-b"
}
]
}
```

</WranglerConfig>

Making it possible for Worker A to call the `add()` method from Worker B:
For TypeScript, generate Worker A's binding types from both configuration files. Run the following command from the `worker-a` directory:

<PackageManagers
type="exec"
pkg="wrangler"
args="types -c ./wrangler.jsonc -c ../worker-b/wrangler.jsonc"
/>

Passing both files lets Wrangler resolve Worker B's default export. The generated `Env` interface types `WORKER_B` as a `Service` with the `add()` method. Do not set `entrypoint` to `default`; omitting `entrypoint` selects the default export.

Worker A can then call `add()`:

<Tabs syncKey="workersExamples">

<TypeScriptExample omitTabs={true}>

```ts
export default {
async fetch(request, env) {
async fetch(_request, env): Promise<Response> {
const result = await env.WORKER_B.add(1, 2);
return new Response(result);
return new Response(result.toString());
},
};
} satisfies ExportedHandler<Env>;
```

</TypeScriptExample>
Expand All @@ -110,3 +132,11 @@ class Default(WorkerEntrypoint):
</TabItem>

</Tabs>

To run both TypeScript Workers locally, run the following command from the `rpc-example` directory. The first configuration is the primary Worker and is available at `http://localhost:8787`.

<PackageManagers
type="exec"
pkg="wrangler"
args="dev -c ./worker-a/wrangler.jsonc -c ./worker-b/wrangler.jsonc"
/>
Loading