Custom Base Controllers

Demonstrates how to extend Katal's Controller class to create reusable base classes with shared beforeHandle / afterHandle lifecycle hooks.

Source: examples/custom-base-controllers/app.ts

What This Covers

Pattern Class What it does
Admin guard AdminController Checks for admin token in beforeHandle, returns 403 if missing
API wrapper ApiController Wraps all responses with { version, timestamp, data } via afterHandle
Auth guard AuthenticatedController Verifies Bearer token in beforeHandle, sets this.user

Run

cd examples/custom-base-controllers
bun run app.ts

Server starts on http://localhost:3000.

Key Pattern

abstract class AdminController extends Controller {
  protected override async beforeHandle(): Promise<Response | null> {
    const auth = this.context.request.headers.get("Authorization");
    if (!auth?.includes("admin-token")) {
      return this.error("Admin access required", 403);
    }
    return null; // continue to handle()
  }
}

class GetAdminStatsController extends AdminController {
  async handle() {
    return this.success({ users: 42, revenue: 9000 });
  }
}

Lifecycle Hooks

Hook Override Return null to Return Response to
beforeHandle() yes continue to handle() short-circuit the request
afterHandle(response) yes transform or replace the response