Middleware Hooks¶
Demonstrates Katal's Middleware interface with before and after hooks. Shows logging, request timing, request ID propagation, and authentication — all as composable middleware objects.
Source: examples/middleware-hooks/app.ts
What This Covers¶
| Middleware | Hook(s) | What it does |
|---|---|---|
loggingMiddleware |
before + after |
Logs method/path before; logs status after |
timingMiddleware |
before + after |
Stores startTime in ctx.state; adds X-Response-Time header |
requestIdMiddleware |
before + after |
Logs correlation id; adds X-Request-ID response header |
authMiddleware |
before |
Validates Bearer token; sets ctx.state.user or returns 401 |
Run¶
cd examples/middleware-hooks
bun run app.ts
Server starts on http://localhost:3000.
Key Pattern¶
import type { Middleware, MiddlewareContext } from "katal";
const timingMiddleware: Middleware = {
async before(ctx: MiddlewareContext) {
ctx.state.startTime = Date.now();
return null; // continue
},
async after(ctx: MiddlewareContext) {
const duration = Date.now() - (ctx.state.startTime as number);
const headers = new Headers(ctx.response!.headers);
headers.set("X-Response-Time", `${duration}ms`);
return new Response(ctx.response!.body, {
status: ctx.response!.status,
headers,
});
},
};
// Register globally
app.use(timingMiddleware);
// Or register as named (applied per-route)
app.middleware("timing", timingMiddleware);
router.get("/profile", ProfileController, { middleware: ["timing"] });
State Sharing Between before and after¶
ctx.state is a plain Record<string, unknown> that persists for the full request lifecycle. Set values in before, read them in after.