API REFERENCE

Controller

import { Controller, type RouteHandler, type Router } from '@rasenganjs/server';

Abstract base class for defining a set of related routes.

abstract class Controller { middlewares: Middleware[]; schemas?: Record<string, SchemaDefinition>; abstract routes(router: Router): void; }
MemberDescription
middlewaresRuns before every route in this controller — after module-level middleware, before route-level middleware
schemasPer-method schema definitions, matched to handlers by function name
routes(router)Register this controller's routes — called during compilation

RouteHandler

type RouteHandler<S extends SchemaDefinition = {}> = ( ctx: Context<InferBody<S>, InferParams<S>, InferQuery<S>> ) => Response | Promise<Response>;

Generic over a SchemaDefinition so ctx.body/ctx.params/ctx.query narrow to the schema's inferred types when one is provided.

Router

import type { Router } from '@rasenganjs/server';

Wraps the Futon router with a middleware-friendly API and automatic schema validation. Passed to Controller.routes().

Method overloads (get/post/put/patch/delete — no head/options)
router.get(path: string, handler: RouteHandler): void; router.get(path: string, middleware: Middleware, handler: RouteHandler): void; router.get(path: string, middlewares: Middleware[], handler: RouteHandler): void; router.get<S>(path: string, handler: RouteHandler<S>, schema: S): void; router.get<S>(path: string, middleware: Middleware, handler: RouteHandler<S>, schema: S): void; router.get<S>(path: string, middlewares: Middleware[], handler: RouteHandler<S>, schema: S): void;

The same six overload shapes exist for post, put, patch, and delete.

Schema Resolution

When a SchemaDefinition is passed as the trailing argument, validation middleware is injected automatically, behind any route-level middleware. When omitted, the router falls back to matching the handler's function name against the controller's schemas dictionary:

class UsersController extends Controller { schemas = { create: { body: CreateUserSchema }, }; routes(router: Router) { router.post('/users', this.create); // resolves schemas.create by name — no 3rd arg needed } create: RouteHandler = async (ctx) => { /* ... */ }; }

Name-based resolution requires the handler to have a .name — arrow function class fields keep the property name (this.create.name === 'create'), but a bound method or reassigned reference may not. Pass the schema explicitly as the trailing argument in that case — doing so is also what triggers TypeScript's schema-aware overload for ctx.body/ctx.params/ctx.query type inference.

ServerApp
Container