Fetch Handler

fest handlers consume a Request-compatible object and return a Response.

Basic Handler

import { serve } from "@hornjs/fest";
import { NodeRuntimeAdapter } from "@hornjs/fest/node";

serve({
  adapter: new NodeRuntimeAdapter(),
  fetch(request) {
    return new Response(`You requested ${request.url}`);
  },
});

The fetch function is the final application handler after middleware has run.

ServerRequest

Handlers and middleware receive ServerRequest, which extends the standard Request with a few server-specific helpers.

request.context

Use invocation context to share per-invocation state across middleware and handlers.

import { createContextKey, serve } from "@hornjs/fest";
import { NodeRuntimeAdapter } from "@hornjs/fest/node";

const requestId = createContextKey<string>("unknown");

serve({
  adapter: new NodeRuntimeAdapter(),
  middleware: [
    async (request, next) => {
      request.context.set(requestId, crypto.randomUUID());
      return next(request);
    },
  ],
  fetch(request) {
    return Response.json({
      id: request.context.get(requestId),
    });
  },
});

request.runtime

request.runtime exposes runtime capabilities needed by helpers such as serveStatic(). This includes file resolution, file access, and compression transforms when supported by the current adapter.

request.waitUntil()

Use waitUntil() to register background work that should finish before the server fully closes.

serve({
  adapter: new NodeRuntimeAdapter(),
  fetch(request) {
    request.waitUntil?.(
      fetch("https://example.com/audit", {
        method: "POST",
        body: JSON.stringify({ url: request.url }),
      }),
    );
    return new Response("ok");
  },
});

request._request and request._url

These are internal convenience fields used by middleware:

  • request._request keeps the original request when middleware replaces or wraps it
  • request._url caches a parsed URL instance

They are available, but most application code should prefer standard request properties and request.context.