Skip to main content

OpenAPIGenerator

Converts oRPC routers and contracts into OpenAPI 3.1.1 documents.
import { OpenAPIGenerator } from '@orpc/openapi'

Constructor

class OpenAPIGenerator {
  constructor(options?: OpenAPIGeneratorOptions)
}

interface OpenAPIGeneratorOptions {
  schemaConverters?: ConditionalSchemaConverter[]
}
schemaConverters
ConditionalSchemaConverter[]
Schema converters to use for translating validation schemas to JSON Schema. Supply at least one (e.g. ZodToJsonSchemaConverter). Multiple converters are tried in order.

generate(router, options?)

generator.generate(
  router: AnyContractRouter | AnyRouter,
  options?: OpenAPIGeneratorGenerateOptions
): Promise<OpenAPI.Document>
router
AnyContractRouter | AnyRouter
required
The oRPC router or contract to convert.
info
OpenAPI.InfoObject
The info object. Defaults to { title: 'API Reference', version: '0.0.0' }.
servers
OpenAPI.ServerObject[]
List of server URLs.
filter
boolean | ((options: TraverseContractProcedureCallbackOptions) => boolean)
Filter function or static boolean. Return false to exclude a procedure from the spec. Defaults to include all procedures.
commonSchemas
Record<string, { schema: AnySchema, strategy?: 'input' | 'output' } | { error: 'UndefinedError' }>
Register schemas as reusable $ref components under #/components/schemas.
customErrorResponseBodySchema
JSONSchema | null | ((errors, status) => JSONSchema | null)
Override the error response body shape. Return null to use oRPC’s default.

Example

import { OpenAPIGenerator } from '@orpc/openapi'
import { ZodToJsonSchemaConverter } from '@orpc/zod/zod4'

const generator = new OpenAPIGenerator({
  schemaConverters: [new ZodToJsonSchemaConverter()],
})

const spec = await generator.generate(router, {
  info: { title: 'Planet API', version: '1.0.0' },
  servers: [{ url: 'https://api.example.com' }],
  commonSchemas: {
    Planet: { schema: PlanetSchema },
  },
  filter: ({ path }) => path[0] !== 'internal',
})

OpenAPIHandler

Serves your oRPC router as a standard OpenAPI-compatible HTTP API. Non-oRPC clients (curl, generated SDKs, etc.) can call it directly.
import { OpenAPIHandler } from '@orpc/openapi/fetch'   // Fetch/Edge runtimes
import { OpenAPIHandler } from '@orpc/openapi/node'    // Node.js

Constructor

class OpenAPIHandler<T extends Context> extends FetchHandler<T> {
  constructor(
    router: Router<any, T>,
    options?: OpenAPIHandlerOptions<T>
  )
}

handle(request, options?)

handler.handle(request, {
  prefix: '/api',
  context: { userId: '123' },
})
prefix
string
URL prefix to strip when matching routes.
context
TContext
Initial context provided to all procedures.

Example (Fetch)

import { OpenAPIHandler } from '@orpc/openapi/fetch'
import { router } from './router'

const handler = new OpenAPIHandler(router)

export default {
  async fetch(request: Request) {
    const response = await handler.handle(request, { context: {} })
    return response ?? new Response('Not found', { status: 404 })
  },
}

OpenAPIReferencePlugin

A plugin that serves an OpenAPI spec and interactive docs UI alongside your handler.
import { OpenAPIReferencePlugin } from '@orpc/openapi/plugins'

Constructor options

schemaConverters
ConditionalSchemaConverter[]
Schema converters for spec generation.
specGenerateOptions
OpenAPIGeneratorGenerateOptions | ((options) => Promisable<OpenAPIGeneratorGenerateOptions>)
Options passed to generator.generate().
specPath
string
default:"/spec.json"
URL path for the OpenAPI JSON spec.
docsPath
string
default:"/"
URL path for the interactive docs UI.
docsProvider
'scalar' | 'swagger'
default:"scalar"
UI library to render.
docsTitle
string | ((options) => Promisable<string>)
default:"API Reference"
Title for the docs page.
new RPCHandler(router, {
  plugins: [
    new OpenAPIReferencePlugin({
      schemaConverters: [new ZodToJsonSchemaConverter()],
      specGenerateOptions: {
        info: { title: 'My API', version: '1.0.0' },
      },
      docsPath: '/docs',
      docsProvider: 'swagger',
    }),
  ],
})

oo.spec()

Customizes the OpenAPI operation object for a given middleware or error map entry. Applied during spec generation.
import { oo } from '@orpc/openapi'

function customOpenAPIOperation<T extends object>(
  o: T,
  extend: Partial<OpenAPI.OperationObject> | ((current, procedure) => OpenAPI.OperationObject)
): T

// Alias:
oo.spec(o, extend)

As a partial merge

const authMiddleware = oo.spec(
  os.middleware(async ({ context, next }) => next()),
  { security: [{ bearerAuth: [] }] },
)

As a function

const authMiddleware = oo.spec(
  os.middleware(async ({ next }) => next()),
  (currentOperation, procedure) => ({
    ...currentOperation,
    security: [{ bearerAuth: [] }],
    'x-requires-auth': true,
  }),
)

CompositeSchemaConverter

Combines multiple ConditionalSchemaConverter instances into one. Tries each converter in order and delegates to the first that matches.
import { CompositeSchemaConverter } from '@orpc/openapi'

class CompositeSchemaConverter implements SchemaConverter {
  constructor(converters: readonly ConditionalSchemaConverter[])

  async convert(
    schema: AnySchema | undefined,
    options: SchemaConvertOptions,
  ): Promise<[required: boolean, jsonSchema: JSONSchema]>
}
Used internally by OpenAPIGenerator. You can also use it directly:
const composite = new CompositeSchemaConverter([
  new ZodToJsonSchemaConverter(),
  new experimental_ValibotToJsonSchemaConverter(),
])

const [required, jsonSchema] = await composite.convert(mySchema, { strategy: 'input' })

SchemaConverter interface

interface SchemaConverter {
  convert(
    schema: AnySchema | undefined,
    options: SchemaConvertOptions,
  ): Promisable<[required: boolean, jsonSchema: JSONSchema]>
}

interface ConditionalSchemaConverter extends SchemaConverter {
  condition(
    schema: AnySchema | undefined,
    options: SchemaConvertOptions,
  ): Promisable<boolean>
}

interface SchemaConvertOptions {
  strategy: 'input' | 'output'
  components?: readonly SchemaConverterComponent[]
  minStructureDepthForRef?: number
}

Build docs developers (and LLMs) love