Middleware
Middleware is the main composition mechanism in fest.
Shape
Middleware receives (request, next) and can:
- return a
Responseimmediately - call
next(request)and return the downstream response - replace or mutate the request before passing it on
import type { ServerMiddleware } from "@hornjs/fest";
const poweredBy: ServerMiddleware = async (request, next) => {
const response = await next(request);
response.headers.set("x-powered-by", "fest");
return response;
};
Registering Middleware
import { serve } from "@hornjs/fest";
import { NodeRuntimeAdapter } from "@hornjs/fest/node";
serve({
adapter: new NodeRuntimeAdapter(),
middleware: [poweredBy],
routes: {
"/": () => new Response("ok"),
},
fetch: () => new Response("Not Found", { status: 404 }),
});
Short-Circuiting
Middleware can stop the chain by returning a response directly.
const auth: ServerMiddleware = async (request, next) => {
if (!request.headers.get("authorization")) {
return new Response("Unauthorized", { status: 401 });
}
return next(request);
};
Static Files
serveStatic() is implemented as middleware.
import { serve } from "@hornjs/fest";
import { serveStatic } from "@hornjs/fest/static";
import { NodeRuntimeAdapter } from "@hornjs/fest/node";
serve({
adapter: new NodeRuntimeAdapter(),
middleware: [serveStatic({ dir: "./public" })],
fetch: () => new Response("Not Found", { status: 404 }),
});
Request Logging
The optional logger lives in a separate subpath export.
import { serve } from "@hornjs/fest";
import { log } from "@hornjs/fest/log";
import { NodeRuntimeAdapter } from "@hornjs/fest/node";
serve({
adapter: new NodeRuntimeAdapter(),
middleware: [log()],
routes: {
"/": () => new Response("ok"),
},
fetch: () => new Response("Not Found", { status: 404 }),
});
Plugins
ServerPlugin runs during Server construction and can modify server.options
or register process-level behavior.
fest itself uses plugins internally for:
- request error normalization
- graceful shutdown handling in supported runtimes