Skip to content

Commit

Permalink
Create Workers + Hono env middleware example
Browse files Browse the repository at this point in the history
  • Loading branch information
djfarrelly committed Jan 10, 2025
1 parent 67c6be4 commit 3fbf725
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 14 deletions.
12 changes: 12 additions & 0 deletions pages/docs/examples/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,15 @@ Send all function failures to Datadog (or similar) for monitoring.
</Card>

</CardGroup>

## Middleware

<CardGroup>
<Card
href={"/docs/examples/middleware/cloudflare-workers-environment-variables"}
title={'Cloudflare Workers & Hono environment variables'}
>
Access environment variables and other Cloudflare bindings within Inngest functions when using Workers or Hono.
</Card>

</CardGroup>
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { CodeGroup } from "src/shared/Docs/mdx";

# Cloudflare Workers environment variables and context

Cloudflare Workers does not set environment variables a global object like Node.js does with `process.env`. Workers [binds environment variables](https://developers.cloudflare.com/workers/configuration/environment-variables/) to the worker's special `fetch` event handler thought a specific `env` argument.

This means accessing environment variables within Inngest function handlers isn't possible without explicitly passing them through from the worker event handler to the Inngest function handler.

We can accomplish this by use the [middleware](/docs/features/middleware) feature for Workers or when using [Hono](/docs/learn/serving-inngest-functions#framework-hono).

## Creating middleware

You can create middleware which extracts the `env` argument from the Workers `fetch` event handler arguments for either Workers or Hono:

1. Use `onFunctionRun`'s `reqArgs` array to get the `env` object and, optionally, cast a type.
2. Return the `env` object within the special `ctx` object of `transformInput` lifecycle method.

<CodeGroup>

```ts {{ title: "Workers" }}
import { Inngest, InngestMiddleware } from 'inngest';

const bindings = new InngestMiddleware({
name: 'Cloudflare Workers bindings',
init({ client, fn }) {
return {
onFunctionRun({ ctx, fn, steps, reqArgs }) {
return {
transformInput({ ctx, fn, steps }) {
// reqArgs is the array of arguments passed to the Worker's fetch event handler
// ex. fetch(request, env, ctx)
// We cast the argument to the global Env var that Wrangler generates:
const env = reqArgs[1] as Env;
return {
ctx: {
// Return the env object to the function handler's input args
env,
},
};
},
};
},
};
},
});

// Include the middleware when creating the Inngest client
export const inngest = new Inngest({
id: 'my-workers-app',
middleware: [bindings],
});
```

```ts {{ title: "Hono" }}
import { Inngest, InngestMiddleware } from 'inngest';
import { type Context } from 'hono';

type Bindings = {
MY_VAR: string;
DB_URL: string;
MY_BUCKET: R2Bucket;
};

const bindings = new InngestMiddleware({
name: 'Hono bindings',
init({ client, fn }) {
return {
onFunctionRun({ ctx, fn, steps, reqArgs }) {
return {
transformInput({ ctx, fn, steps }) {
// reqArgs is the array of arguments passed to a Hono handler
// We cast the argument to the correct Hono Context type with our
// environment variable bindings
const [honoCtx] = reqArgs as [Context<{ Bindings: Bindings }>];
return {
ctx: {
// Return the context's env object to the function handler's input args
env: honoCtx.env,
},
};
},
};
},
};
},
});

// Include the middleware when creating the Inngest client
export const inngest = new Inngest({
id: 'my-hono-app',
middleware: [bindings],
});
```

</CodeGroup>

Within your functions, you can now access the environment variables via the `env` object argument that you returned in `transformInput` above. Here's an example function:

```ts
const myFn = inngest.createFunction(
{ id: 'my-fn' },
{ event: 'demo/event.sent' },
// The "env" argument returned in transformInput is passed through:
async ({ event, step, env }) => {

// The env object will be typed as well:
console.log(env.MY_VAR);
}
);
```
10 changes: 7 additions & 3 deletions pages/docs/features/middleware/create.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import {
RiMistFill,
RiPlugLine,
RiTerminalBoxLine,
RiKeyLine,
} from "@remixicon/react";

# Creating a middleware
# Creating middleware

Creating middleware means defining the lifecycles and subsequent hooks in those lifecycles to run code in. Lifecycles are actions such as a function run or sending events, and individual hooks within those are where we run code, usually with a _before_ and _after_ step.

Expand Down Expand Up @@ -39,7 +40,7 @@ Creating middleware means defining the lifecycles and subsequent hooks in those
middleware: [myMiddleware],
});
```

</GuideSection>

<GuideSection show="python">
Expand Down Expand Up @@ -340,7 +341,7 @@ It's common for middleware to require additional customization or options from d

## Next steps

Check out our pre-build middleware and examples:
Check out our pre-built middleware and examples:

<CardGroup cols={2}>
<Card title="Dependency Injection" icon={<RiPlugLine className="text-basis h-4 w-4" />} href={'/docs/features/middleware/dependency-injection'}>
Expand All @@ -355,6 +356,9 @@ Check out our pre-build middleware and examples:
<Card title="Datadog middleware" icon={<RiTerminalBoxLine className="text-basis h-4 w-4"/>} href={'/docs/examples/track-failures-in-datadog'}>
Add tracing with Datadog under a few minutes.
</Card>
<Card title="Cloudflare Workers & Hono middleware" icon={<RiKeyLine className="text-basis h-4 w-4"/>} href={'/docs/examples/middleware/cloudflare-workers-environment-variables'}>
Access environment variables within Inngest functions.
</Card>
</CardGroup>


Expand Down
56 changes: 47 additions & 9 deletions pages/docs/learn/serving-inngest-functions.mdx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Callout, CodeGroup, VersionBadge, GuideSelector, GuideSection } from "shared/Docs/mdx";
import { Callout, Tip, CodeGroup, VersionBadge, GuideSelector, GuideSection, Col, Row } from "shared/Docs/mdx";

export const description = `Serve the Inngest API as an HTTP endpoint in your application.`
export const hidePageSidebar = true;
Expand Down Expand Up @@ -32,13 +32,41 @@ serve({
});
```

<Callout>
You will find the complete list of supported frameworks below.
</Callout>

## Supported Platforms

Below you will find a list of framework-specific bindings, as well as instructions on adding bindings to [custom platforms](#custom-frameworks)!
## Supported frameworks and platforms

<div className="grid md:grid-cols-3">

<Col>
* [Astro](#framework-astro)
* [AWS Lambda](#framework-aws-lambda)
* [Bun](#bun-serve)
* [Cloudflare Pages](#framework-cloudflare-pages-functions)
* [Cloudflare Workers](#framework-cloudflare-workers)
* [DigitalOcean Functions](#framework-digital-ocean-functions)
* [Express](#framework-express)
</Col>
<Col>
* [Fastify](#framework-fastify)
* [Fresh (Deno)](#framework-fresh-deno)
* [Google Cloud Run Functions](#framework-google-cloud-run-functions)
* [Firebase Cloud functions](#framework-firebase-cloud-functions)
* [H3](#framework-h3)
* [Hono](#framework-hono)
* [Koa](#framework-koa)
</Col>
<Col>
* [NestJS](#framework-nest-js)
* [Next.js](#framework-next-js)
* [Nitro](#framework-nitro)
* [Nuxt](#framework-nuxt)
* [Redwood](#framework-redwood)
* [Remix](#framework-remix)
* [SvelteKit](#framework-svelte-kit)
</Col>

</div>

You can also create a custom serve handler for any framework or platform not listed here - [read more here](#custom-frameworks).

<Callout variant="info">
Want us to add support for another framework? Open an issue on [GitHub](https://github.com/inngest/website) or tell us about it on our [Discord](/discord).
Expand Down Expand Up @@ -155,11 +183,17 @@ export default {
fetch: serve({
client: inngest,
functions: [fnA],
// We suggest explicitly defining the path to serve Inngest functions
servePath: "/api/inngest",
}),
};
```
</CodeGroup>

<Tip>
To automatically pass environment variables defined with Wrangler to Inngest function handlers, use the [Cloudflare Workers bindings middleware](/docs/examples/middleware/cloudflare-workers-environment-variables).
</Tip>

When developing locally with Wrangler and the `--remote` flag, your code is
deployed and run remotely. To use this with a local Inngest Dev Server, you must
use a tool such as [ngrok](https://ngrok.com/) or
Expand Down Expand Up @@ -488,7 +522,7 @@ See the [github.com/unjs/h3](https://github.com/unjs/h3) repository for more inf

### Framework: Hono

Add the following to `./src/index.ts`:
Inngest supports the [Hono](https://hono.dev/) framework which is popularly deployed to Cloudflare Workers. Add the following to `./src/index.ts`:

<CodeGroup>
```ts
Expand All @@ -511,6 +545,10 @@ export default app;
```
</CodeGroup>

<Tip>
To automatically pass environment variables defined with Wrangler to Inngest function handlers, use the [Hono bindings middleware](/docs/examples/middleware/cloudflare-workers-environment-variables).
</Tip>

See the [Hono example](https://github.com/inngest/inngest-js/blob/main/examples/framework-hono) for more information.

### Framework: Koa <VersionBadge version="v3.6.0+" />
Expand Down
11 changes: 10 additions & 1 deletion pages/docs/reference/middleware/examples.mdx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Callout, CodeGroup, Properties, Property, Row, Col, VersionBadge } from "src/shared/Docs/mdx";
import { Callout, CodeGroup, Properties, Property, Row, Col, VersionBadge, Card, CardGroup } from "src/shared/Docs/mdx";
import { RiKeyLine } from "@remixicon/react"

# Example middleware <VersionBadge version="v2.0.0+" />

Expand All @@ -8,6 +9,7 @@ The following examples show how you might use middleware in some real-world scen
- [Common actions for every function](#common-actions-for-every-function)
- [Logging](#logging)
- [Prisma in function context](#prisma-in-function-context)
- [Cloudflare Workers & Hono environment variables](/docs/examples/middleware/cloudflare-workers-environment-variables)

---

Expand Down Expand Up @@ -283,3 +285,10 @@ const prismaMiddleware = new InngestMiddleware({

Check out [Common actions for every function](/docs/reference/middleware/examples#common-actions-for-every-function) to see how this technique can be used to create steps for all of your unique logic.

## Other examples

<CardGroup cols={2}>
<Card title="Cloudflare Workers & Hono middleware" icon={<RiKeyLine className="text-basis h-4 w-4"/>} href={'/docs/examples/middleware/cloudflare-workers-environment-variables'}>
Access environment variables within Inngest functions.
</Card>
</CardGroup>
12 changes: 11 additions & 1 deletion shared/Docs/navigationStructure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@ const sectionHome: (NavGroup | NavLink)[] = [
href: `/docs/features/middleware`,
},
{
title: "Creating a middleware",
title: "Creating middleware",
href: `/docs/features/middleware/create`,
},
{
Expand Down Expand Up @@ -864,6 +864,16 @@ const sectionExamples: NavGroup[] = [
},
],
},
{
title: "Middleware",
defaultOpen: true,
links: [
{
title: "Cloudflare Workers & Hono environment variables",
href: `/docs/examples/middleware/cloudflare-workers-environment-variables`,
},
],
},
];

export const isNavGroup = (
Expand Down

0 comments on commit 3fbf725

Please sign in to comment.