Controller
Grouping for routes that share a path prefix and a common preamble.
A Controller is a thin factory: each method constructs the corresponding RouteBase subclass with the prefix already joined on, records its id, and returns it. The routes are ordinary routes registered on the nearest App exactly as if they had been constructed directly — a controller adds no dispatch layer of its own.
import { Controller } from "@ozanarslan/corpus";
const users = new Controller("/users");
users.beforeEach = (c) => authenticate(c);
users.route("GET /:id", (c) => findUser(c.params.id));Contents
Controller
class
class Controller<Px extends Optional<string>= Optional<string>>Registers routes under a shared path prefix.
Every method mirrors the constructor of the route class it creates, so moving a route into a controller means changing the call site and nothing else. The prefix is folded into the endpoint at construction time and into the endpoint type through WithPrefix, so the returned route stays as narrowly typed as one written out by hand.
Controller.beforeEach runs ahead of the handler for the route kinds that have a user-supplied handler — Controller.route and Controller.staticRoute. The other kinds resolve their responses internally and are unaffected.
Controller.routeIds makes the group addressable afterwards, which is how a Middleware can be attached to every route in a controller at once.
Type parameters
Px— The literal prefix type, carried into every endpoint type the controller produces.
Controller.constructor()
constructor(public prefix?: Px)Creates a controller.
Parameters
prefix— Path segment prepended to every endpoint registered through this controller. Omit it to group routes without changing their paths — the shared Controller.beforeEach and Controller.routeIds still apply.
Controller.routeIds
readonly routeIds: Set<string>Ids of every RouteBase registered through this controller, in the order they were created.
Pass them to a Middleware to target the whole group:
new Middleware([...users.routeIds], handler);Controller.beforeEach
beforeEach?: ContextHandlerRuns before the handler of every Controller.route and Controller.staticRoute created by this controller.
Its return value is discarded — this is for side effects on the Context, such as authenticating a request or populating Context.data. Throwing here aborts the request before the handler runs, which is the intended way to reject one.
Assign it before registering routes: each route captures the controller, not the function, but a route registered while it is unset still checks it at request time. For behaviour that must wrap the response as well as precede it, use a Middleware targeting Controller.routeIds instead.
Controller.route()
route<B = unknown, S = unknown, P = unknown, R = unknown, E extends string = string>(...args: ConstructorParameters<typeof Route<B, S, P, R, E>>): Route<B, S, P, R, WithPrefix<Px, E>>Registers a dynamic route under this controller. Behaves identically to Route but automatically prepends the controller prefix and runs beforeEach before the handler.
Type parameters
B— Parsed Context.body type.S— Parsed Context.search type.P— Parsed Context.params type.R— Response body type.E— The endpoint literal, before the prefix is applied.
Parameters
args— TheRouteconstructor arguments: the route address (a"METHOD /endpoint"string or a method/endpoint pair), the ContextHandler, and an optional RouteConfig.
Returns — The registered Route, its endpoint type prefixed.
Controller.staticRoute()
staticRoute<B = unknown, S = unknown, P = unknown, E extends string = string>(...args: ConstructorParameters<typeof StaticRoute<B, S, P, E>>): StaticRoute<B, S, P, WithPrefix<Px, E>>Registers a static route under this controller. Behaves identically to StaticRoute but automatically prepends the controller prefix.
Controller.beforeEach runs only when a callback is supplied, since that is where the controller has a handler to wrap; a static route that just serves its file is left alone.
Type parameters
B— Parsed Context.body type.S— Parsed Context.search type.P— Parsed Context.params type.E— The endpoint literal, before the prefix is applied.
Parameters
args— TheStaticRouteconstructor arguments: the route address, the file path, an optional callback receiving theContextand the file contents, and an optional RouteConfig.
Returns — The registered StaticRoute, its endpoint type prefixed.
Controller.fileRoute()
fileRoute<E extends string = string>(...args: ConstructorParameters<typeof FileRoute<E>>): FileRoute<WithPrefix<Px, E>>Registers a file route under this controller. Behaves identically to FileRoute but automatically prepends the controller prefix.
Controller.beforeEach does not apply: a file route resolves its response internally and takes no handler to wrap.
Type parameters
E— The endpoint literal, before the prefix is applied.
Parameters
args— TheFileRouteconstructor arguments: the route address and the file definition.
Returns — The registered FileRoute, its endpoint type prefixed.
Controller.websocketRoute()
websocketRoute<E extends string = string>(...args: ConstructorParameters<typeof WebSocketRoute<E>>): WebSocketRoute<WithPrefix<Px, E>>Registers a websocket route under this controller. Behaves identically to WebSocketRoute but automatically prepends the controller prefix.
The address is a plain endpoint rather than a method-and-endpoint pair, since an upgrade is always a Method.GET. Controller.beforeEach does not apply — the socket lifecycle callbacks are not a ContextHandler.
Type parameters
E— The endpoint literal, before the prefix is applied.
Parameters
args— TheWebSocketRouteconstructor arguments: the endpoint followed by the socket lifecycle callbacks.
Returns — The registered WebSocketRoute, its endpoint type prefixed.
Controller.bundleRoute()
bundleRoute<E extends string = string>(...args: ConstructorParameters<typeof BundleRoute<E>>): BundleRoute<WithPrefix<Px, E>>Registers a bundle route under this controller. Behaves identically to BundleRoute but automatically prepends the controller prefix.
Controller.beforeEach does not apply: a bundle route resolves files internally and takes no handler to wrap.
Type parameters
E— The endpoint literal, before the prefix is applied.
Parameters
args— TheBundleRouteconstructor arguments: the endpoint, the directory to serve, and an optionalBundleRouteDefinition.
Returns — The registered BundleRoute, its endpoint type prefixed.