Decorators or plain routes
Prefer route functions? Use them. Prefer controllers? Use standard TypeScript 5 decorators. Both run through the same router.
Route functions
export function plainApp(service: GreetingService) {
const app = createApp();
app.router.get("/readers/:id", (req, res) => {
res.json({ message: service.message(toHttpId(req.param("id"))) });
});
app.router.head("/readers/:id", (req, res) => {
toHttpId(req.param("id"));
res.header("content-type", "application/json; charset=utf-8").send("");
});
return app;
}Controller methods
@Controller("/readers")
export class ReadersController {
constructor(private readonly service: GreetingService) {}
@Get("/:id")
show(req: Request, res: Response): void {
res.json({ message: this.service.message(toHttpId(req.param("id"))) });
}
@Head("/:id")
head(req: Request, res: Response): void {
toHttpId(req.param("id"));
res.header("content-type", "application/json; charset=utf-8").send("");
}
}Construct the controller yourself and pass it to registerControllers(router, instance). The complete example uses the same greeting service and ID validation in both versions.
Import decorators from @portablesheep/brevity/decorators, not the default core entry point. Leave legacy experimentalDecorators and emitDecoratorMetadata disabled. Use public instance methods and keep request-specific state in locals: one controller instance is reused across requests.
Both implementations explicitly register HEAD and map expected domain errors. Run npm run docs:check to verify equivalent GET/HEAD/422 responses. The API reference covers inheritance, path joining, and override semantics.