defineRoute
Explicit route definition with full schema control.
For full control, wrap a handler with defineRoute. Works the same across
Express, Fastify, Hono, and Koa:
const { defineRoute, s } = require('doctreen/express');
// const { defineRoute, s } = require('doctreen/fastify');
// import { defineRoute, s } from 'doctreen/hono';
// const { defineRoute, s } = require('doctreen/koa');
app.post('/users', defineRoute(
(req, res) => {
res.status(201).json({ id: 1, name: req.body.name });
},
{
description: 'Create a new user account',
headers: {
Authorization: 'Bearer <token>',
'Content-Type': 'application/json',
},
request: {
body: s.object({ name: s.string(), email: s.string(), role: s.optional(s.string()) }),
query: null,
},
response: s.object({ id: s.number(), name: s.string(), email: s.string() }),
errors: {
409: 'Email address already in use',
422: { description: 'Validation failed', schema: s.object({ message: s.string(), field: s.string() }) },
},
}
));Schema resolution order
| Adapter | Priority |
|---|---|
| Express | defineRoute → JSDoc → runtime inference |
| Fastify | defineRoute → Fastify native JSON Schema → JSDoc |
| Hono | defineRoute → JSDoc |
| Koa | defineRoute → JSDoc |
| NestJS | @DocRoute / @Doc* decorators |
Options
| Option | Type | Notes |
|---|---|---|
description | string | Human-readable description shown in the UI |
summary | string | Short title for the operation |
headers | Record<string, string> | Request headers — example value as the map value |
request.body | Zod | SchemaNode | Request body |
request.query | Zod | SchemaNode | Query parameters |
response | Zod | SchemaNode | Success response (200 / 201) |
errors | Record<number, string | { description?, schema? }> | Documented error responses |
validate | boolean | Per-route override of adapter-level validate setting |
tags | string[] | Override the path-segment default tag |
security | Array<Record<string, string[]>> | Per-route security override |
hidden | boolean | Hide from docs UI and OpenAPI |
examples | RouteExamples | Multi-example bodies and responses (v1.11+) |
callbacks | Record<string, CallbackDef> | Per-operation OpenAPI 3.1 callbacks |
With TypeScript generics
import { defineRoute, RouteSchemas } from 'doctreen/express';
import { s } from 'doctreen';
app.post('/users', defineRoute<{ name: string }, never, { id: number; name: string }>(
(req, res) => res.status(201).json({ id: 1, name: req.body.name }),
{
description: 'Create a user',
request: { body: s.object({ name: s.string() }) },
response: s.object({ id: s.number(), name: s.string() }),
}
));See TypeScript for the full type catalogue.