sdk/worker | RedwoodSDK
RedwoodSDK

sdk/worker

The RedwoodSDK 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.

defineApp

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.

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")),
]);

requestInfo: RequestInfo

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