@davaux/swagger
Generates an OpenAPI 3.0 spec from your route files and serves a Swagger UI at /docs. Works with any Davaux app that uses defineHandler API routes — no annotations or decorators required.
Installation
npm install @davaux/swagger
Setup
Add it as middleware in src/middleware.ts so it runs before route dispatch:
// src/middleware.ts
import { defineMiddleware } from 'davaux'
import { swagger } from '@davaux/swagger'
const swaggerMw = swagger({
routesDir: process.env.NODE_ENV === 'production' ? './dist' : './.davaux/routes',
info: {
title: 'My API',
version: '1.0.0',
description: 'REST API built with Davaux',
},
})
export default defineMiddleware((ctx, next) => swaggerMw(ctx, next))
Then visit /docs in your browser while running davaux dev or davaux start.
Options
| Option | Type | Default | Description |
|---|---|---|---|
routesDir | string | — | Directory containing compiled route files (see below) |
info.title | string | 'API' | OpenAPI info title |
info.version | string | '1.0.0' | OpenAPI info version |
info.description | string | — | Optional description |
path | string | '/docs' | URL for the Swagger UI page |
specPath | string | '/openapi.json' | URL for the raw OpenAPI JSON |
routesDir
Points to the directory of compiled .js route files that @davaux/swagger introspects. The correct path depends on your environment:
| Mode | routesDir |
|---|---|
davaux dev | ./.davaux/routes |
davaux start | ./dist |
The process.env.NODE_ENV check shown in the setup example is the simplest way to handle both automatically.
What gets documented
Only defineHandler API routes are included. Page routes (.page.tsx) serve HTML and are skipped. Every API route becomes an operation in the spec:
- URL pattern → OpenAPI path (
/api/users/:id→/api/users/{id}) - Route type → HTTP method (
.get.ts→GET,.post.ts→POST, etc.) - URL params → path parameter objects with
in: 'path' - Catch-all params (
[...slug]) →{slug}path parameters
Zod schema extraction
If zod-to-json-schema is installed, @davaux/swagger automatically converts named *Schema exports from your route files into OpenAPI request body schemas:
npm install zod-to-json-schema
// src/routes/api/users.post.ts
import { defineHandler } from 'davaux'
import { z } from 'zod'
// Named export ending in "Schema" — picked up automatically
export const CreateUserSchema = z.object({
name: z.string().min(1),
email: z.string().email(),
role: z.enum(['admin', 'member']).default('member'),
})
export default defineHandler(async (ctx) => {
const input = await ctx.json(CreateUserSchema)
// ...
})
The spec will include the Zod schema as a JSON Schema requestBody on the POST operation. If zod-to-json-schema is not installed, the request body is simply omitted — no error is thrown.
Raw spec
The OpenAPI JSON is available at /openapi.json (or your custom specPath). Use it with any OpenAPI tooling — code generators, Postman, Insomnia, etc.:
curl http://localhost:3000/openapi.json | jq .
The spec is generated once on the first request and cached for the lifetime of the process. Restart the server after adding or removing routes.
Restricting access
In production you may want to put the docs behind authentication. Do it in src/middleware.ts before the swagger middleware:
import { defineMiddleware } from 'davaux'
import { swagger } from '@davaux/swagger'
const swaggerMw = swagger({ routesDir: './dist', info: { title: 'My API', version: '1.0.0' } })
export default defineMiddleware(async (ctx, next) => {
const path = ctx.req.url?.split('?')[0]
if (path === '/docs' || path === '/openapi.json') {
if (ctx.req.headers['x-docs-token'] !== process.env.DOCS_TOKEN) {
ctx.res.writeHead(401, { 'Content-Type': 'text/plain' })
ctx.res.end('Unauthorized')
return
}
}
return swaggerMw(ctx, next)
})