openapi() Function
The openapi() function is the primary declarative API for generating an OpenAPI document from a single definition object. It accepts a complete specification of your API -- info, routes, schemas, plugins, and metadata -- and returns a frozen OpenAPIDocument.
Import
import { openapi } from 'to-openapi'Signature
function openapi(definition: ToOpenapiDefinition): OpenAPIDocumentParameters
definition: ToOpenapiDefinition
A single object describing the entire API. The full interface is:
interface ToOpenapiDefinition {
info: InfoObject
paths: Record<string, RouteShorthand>
schemas?: Record<string, StandardJSONSchemaV1>
plugins?: ToOpenapiPlugin[]
openapi?: "3.0.3" | "3.1.0"
servers?: ServerObject[]
security?: SecurityRequirementObject[]
securitySchemes?: Record<string, SecuritySchemeObject>
tags?: TagObject[]
externalDocs?: ExternalDocsObject
}info (required)
Type: InfoObject
Metadata about the API. This maps directly to the OpenAPI info object.
interface InfoObject {
title: string
version: string
description?: string
termsOfService?: string
contact?: {
name?: string
url?: string
email?: string
}
license?: {
name: string
url?: string
}
}title(required) -- the name of your API.version(required) -- the version string for your API (e.g."1.0.0").description-- a longer description of the API. Supports Markdown.termsOfService-- a URL to the terms of service.contact-- contact information (name, url, email).license-- license information with a requirednameand optionalurl.
paths (required)
Type: Record<string, RouteShorthand>
An object whose keys are route keys in the format "METHOD /path" and whose values are route shorthand definitions. The method is case-insensitive (e.g. "GET /users" and "get /users" are both valid) and the path must start with /.
{
"GET /users": { ... },
"POST /users": { ... },
"GET /users/{id}": { ... },
"DELETE /users/{id}": { ... },
}See the Types reference for the full RouteShorthand interface.
schemas (optional)
Type: Record<string, StandardJSONSchemaV1>
Named schemas that will be placed in components.schemas in the output document. Other routes can reference these schemas via $ref. Each key becomes the schema name in the components section.
{
schemas: {
User: userSchema,
Error: errorSchema,
}
}plugins (optional)
Type: ToOpenapiPlugin[]
An array of plugins that can transform routes, schemas, and the final document during generation. See the Plugin Interface reference for details.
openapi (optional)
Type: "3.0.3" | "3.1.0"
Default: "3.1.0"
The OpenAPI specification version to target. This affects how schemas are resolved and output.
servers (optional)
Type: ServerObject[]
A list of server objects describing where the API is hosted.
interface ServerObject {
url: string
description?: string
variables?: Record<string, {
default: string
enum?: string[]
description?: string
}>
}security (optional)
Type: SecurityRequirementObject[]
Global security requirements applied to all operations unless overridden at the operation level.
interface SecurityRequirementObject {
[name: string]: string[]
}securitySchemes (optional)
Type: Record<string, SecuritySchemeObject>
Security scheme definitions that will be placed in components.securitySchemes.
interface SecuritySchemeObject {
type: "apiKey" | "http" | "oauth2" | "openIdConnect"
description?: string
name?: string
in?: "query" | "header" | "cookie"
scheme?: string
bearerFormat?: string
flows?: Record<string, unknown>
openIdConnectUrl?: string
}tags (optional)
Type: TagObject[]
Tag definitions for grouping operations.
interface TagObject {
name: string
description?: string
externalDocs?: ExternalDocsObject
}externalDocs (optional)
Type: ExternalDocsObject
A pointer to external documentation for the API.
interface ExternalDocsObject {
url: string
description?: string
}Return Value
Returns a deeply frozen OpenAPIDocument object. The document is frozen using Object.freeze recursively, making it fully immutable. Attempting to modify any property on the returned document will throw a TypeError in strict mode.
Full Example
import { openapi } from 'to-openapi'
import { z } from 'zod'
import { toJsonSchema } from '@valibot/to-json-schema'
const doc = openapi({
openapi: '3.1.0',
info: {
title: 'Pet Store API',
version: '1.0.0',
description: 'A sample API for managing pets',
contact: {
name: 'API Support',
email: 'support@petstore.example.com',
},
license: {
name: 'MIT',
},
},
servers: [
{ url: 'https://api.petstore.example.com/v1', description: 'Production' },
{ url: 'http://localhost:3000/v1', description: 'Local development' },
],
securitySchemes: {
bearerAuth: {
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
},
},
security: [{ bearerAuth: [] }],
tags: [
{ name: 'pets', description: 'Pet management' },
{ name: 'health', description: 'Health checks' },
],
schemas: {
Pet: z.object({
id: z.string().uuid(),
name: z.string(),
species: z.enum(['dog', 'cat', 'bird']),
}),
Error: z.object({
code: z.number(),
message: z.string(),
}),
},
paths: {
'GET /pets': {
summary: 'List all pets',
tags: ['pets'],
query: z.object({
limit: z.number().int().optional(),
offset: z.number().int().optional(),
}),
200: z.array(z.object({
id: z.string(),
name: z.string(),
species: z.string(),
})),
},
'POST /pets': {
summary: 'Create a pet',
tags: ['pets'],
body: z.object({
name: z.string(),
species: z.enum(['dog', 'cat', 'bird']),
}),
201: z.object({
id: z.string(),
name: z.string(),
species: z.string(),
}),
400: z.object({
code: z.number(),
message: z.string(),
}),
},
'GET /pets/{id}': {
summary: 'Get a pet by ID',
tags: ['pets'],
params: z.object({
id: z.string().uuid(),
}),
200: z.object({
id: z.string(),
name: z.string(),
species: z.string(),
}),
404: null,
},
'GET /health': {
summary: 'Health check',
tags: ['health'],
security: [],
200: z.object({ status: z.literal('ok') }),
},
},
})
// doc is a frozen OpenAPIDocument
console.log(JSON.stringify(doc, null, 2))Notes
- The route key format must be
"METHOD /path"where method is one of:GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS,TRACE(case-insensitive). An invalid route key throws aToOpenapiErrorwith codeINVALID_ROUTE_KEY. - Duplicate method+path combinations within the same definition throw a
ToOpenapiErrorwith codeDUPLICATE_PATH. - Duplicate schema names throw a
ToOpenapiErrorwith codeDUPLICATE_SCHEMA. - Numeric keys in a route shorthand (e.g.
200,404) are treated as HTTP status code responses. - A string value for a status code (e.g.
200: 'User') is treated as a reference to a named schema registered viaschemas. The string must match a registered schema name. - A
nullvalue for a status code produces a response with no content body. - If you need to build the document incrementally, consider using the
OpenAPIclass instead.