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.