Skip to content

11. OpenAPI documents ​

Status: Runnable. Everything on this page works today.

@avijs/openapi builds an OpenAPI 3.1 document from an initialized app: every route, including routes created at runtime, with parameters, request bodies and responses taken from route schemas.

ts
import { createAvi } from '@avijs/core';
import { generateOpenApi } from '@avijs/openapi';

const app = createAvi().register(AppModule);
await app.init();

const document = generateOpenApi(app, {
  info: { title: 'Greeter API', version: '1.0.0' },
  servers: [{ url: 'https://api.example.com' }],
});

Serve it from the app itself:

ts
const docs = defineController({
  routes: [{ method: 'GET', path: '/openapi.json', handler: () => document }],
});

What ends up in the document ​

From the routeIn the document
/users/:idpath /users/{id} with a required id parameter
a trailing *a {wildcard} path parameter
schema.paramsthe parameter schemas
schema.queryone query parameter per property, required as in the schema
schema.bodya required JSON request body
schema.responsethe 200 response body
any input schemaa 400 response with the validation error shape
openapi: { ... }summary, description, tags, operationId, deprecated

Add the documentation fields to a route, or to a route decorator:

ts
route({
  method: 'GET',
  path: '/:id',
  schema: { params: UserId, response: PublicUser },
  openapi: { summary: 'Get a user', tags: ['users'] },
  handler: (ctx) => users.find(ctx.input.params.id),
});

@Get('/:id', { schema: { params: UserId }, openapi: { summary: 'Get a user' } })

Turning schemas into JSON Schema ​

Validation schemas and JSON Schema are different things, so the generator needs a converter:

  • Schemas that implement the Standard JSON Schema extension (~standard.jsonSchema) are converted automatically.
  • Otherwise pass toJsonSchema. For Valibot, @valibot/to-json-schema does the work; Zod 4 has z.toJSONSchema:
ts
import { toJsonSchema } from '@valibot/to-json-schema';

generateOpenApi(app, {
  info: { title: 'Greeter API', version: '1.0.0' },
  toJsonSchema: (schema) => toJsonSchema(schema as never),
});

Without a converter, the route is still documented, with an empty schema where the body would be.

Next ​

Chapter 12: Security headers and CORS.

Released under the MIT License.