Skip to content

sdk/worker

The rwsdk/worker module exports the defineApp function, which is the entry point for your Cloudflare Worker.

This is the shape of a Cloudflare Worker:

export default {
fetch: (request: Request) => {
return new Response("Hello, World!");
},
};

This is the shape of a RedwoodSDK Worker:

import { defineApp } from "rwsdk/worker";
const app = defineApp([/* routes */]);
export default {
fetch: app.fetch,
};

You can also wrap the fetch method to add global error handling:

import { defineApp, ErrorResponse } from "rwsdk/worker";
const app = defineApp([/* routes */]);
export default {
fetch: async (request: Request, env: Env, ctx: ExecutionContext) => {
try {
return await app.fetch(request, env, ctx);
} catch (error) {
// Handle all unhandled errors globally
if (error instanceof ErrorResponse) {
return new Response(error.message, { status: error.code });
}
// Send to monitoring service asynchronously
// Use waitUntil to prevent the worker from being killed
// before the async operation completes
ctx.waitUntil(
sendToMonitoring(error).catch((monitoringError) => {
console.error("Failed to send error to monitoring:", monitoringError);
}),
);
// Log and return generic error response
console.error("Unhandled error:", error);
return new Response("Internal Server Error", { status: 500 });
}
},
};

Note: When sending errors to monitoring services, use ctx.waitUntil() to ensure the worker doesn’t terminate before async operations complete.

For more details on error handling, see the router error handling documentation.

The defineApp function is used to manage how Cloudflare Workers should process requests and subsequently return a response.

import { defineApp } from 'rwsdk/worker'
import { route } from 'rwsdk/router'
defineApp([
// Middleware
function middleware1({ request, ctx }) {
ctx.var1 = 'we break'
},
function middleware1({ request, ctx }) {
ctx.var1 = ctx.var1 + ' abstractions'
},
// Route handlers
route('/', ({ ctx }) => new Response(ctx.var1)), // we break abstractions
route('/ping', () => new Response('pong!')),
]);
---
In this example above a request would be processed by the middleware, then the correct route would match and execute the handler.
---
## `ErrorResponse`
The `ErrorResponse` class is used to return an errors that includes a status code, a message, and a stack trace. You'll be able to extract this information in try-catch blocks, handle it, or return a proper request response.
```ts
import { ErrorResponse } from "rwsdk/worker";
export default defineApp([
async ({ ctx, request, response }) => {
try {
ctx.session = await sessions.load(request);
} catch (error) {
if (error instanceof ErrorResponse && error.code === 401) {
await sessions.remove(request, response.headers);
response.headers.set("Location", "/user/login");
return new Response(null, {
status: 302,
headers: response.headers,
});
}
throw error;
}
},
route("/", () => new ErrorResponse(404, "Not Found")),
]);

The requestInfo object is used to get information about the current request. It’s a singleton that’s populated for each request, and contains the following information.

  • request: The incoming HTTP Request object
  • response: A ResponseInit object used to configure the status and headers of the response
  • ctx: The app context (same as what’s passed to components)
  • rw: RedwoodSDK-specific context
  • cf: Cloudflare’s Execution Context API