Getting Started
OpenAPI is a widely adopted standard for describing RESTful APIs. With oRPC, you can easily publish OpenAPI-compliant APIs with minimal effort.
oRPC is inherently compatible with OpenAPI, but you may need additional configurations such as path prefixes, custom routing, or including headers, parameters, and queries in inputs and outputs. This guide explains how to make your oRPC setup fully OpenAPI-compatible. It assumes basic knowledge of oRPC or familiarity with the Getting Started guide.
Prerequisites
- Node.js 18+ (20+ recommended) | Bun | Deno | Cloudflare Workers
- A package manager: npm | pnpm | yarn | bun | deno
- A TypeScript project (strict mode recommended)
Installation
npm install @orpc/server@latest @orpc/client@latest @orpc/openapi@latest
yarn add @orpc/server@latest @orpc/client@latest @orpc/openapi@latest
pnpm add @orpc/server@latest @orpc/client@latest @orpc/openapi@latest
bun add @orpc/server@latest @orpc/client@latest @orpc/openapi@latest
deno install npm:@orpc/server@latest npm:@orpc/client@latest @orpc/openapi@latest
Defining Routes
This snippet is based on the Getting Started guide. Please read it first.
import type { IncomingHttpHeaders } from 'node:http'
import { ORPCError, os } from '@orpc/server'
import { z } from 'zod'
const PlanetSchema = z.object({
id: z.number().int().min(1),
name: z.string(),
description: z.string().optional(),
})
export const listPlanet = os
.route({ method: 'GET', path: '/planets' })
.input(z.object({
limit: z.number().int().min(1).max(100).optional(),
cursor: z.number().int().min(0).default(0),
}))
.output(z.array(PlanetSchema))
.handler(async ({ input }) => {
// your list code here
return [{ id: 1, name: 'name' }]
})
export const findPlanet = os
.route({ method: 'GET', path: '/planets/{id}' })
.input(z.object({ id: z.coerce.number().int().min(1) }))
.output(PlanetSchema)
.handler(async ({ input }) => {
// your find code here
return { id: 1, name: 'name' }
})
export const createPlanet = os
.$context<{ headers: IncomingHttpHeaders }>()
.use(({ context, next }) => {
const user = parseJWT(context.headers.authorization?.split(' ')[1])
if (user) {
return next({ context: { user } })
}
throw new ORPCError('UNAUTHORIZED')
})
.route({ method: 'POST', path: '/planets' })
.input(PlanetSchema.omit({ id: true }))
.output(PlanetSchema)
.handler(async ({ input, context }) => {
// your create code here
return { id: 1, name: 'name' }
})
export const router = {
planet: {
list: listPlanet,
find: findPlanet,
create: createPlanet
}
}
Key Enhancements:
.route
defines HTTP methods and paths..output
enables automatic OpenAPI spec generation.z.coerce
ensures correct parameter parsing.
For handling headers, queries, etc., see Input/Output Structure. For auto-coercion, see Zod Smart Coercion Plugin. For more .route
options, see Routing.
Creating a Server
import { createServer } from 'node:http'
import { OpenAPIHandler } from '@orpc/openapi/node'
import { CORSPlugin } from '@orpc/server/plugins'
const handler = new OpenAPIHandler(router, {
plugins: [new CORSPlugin()]
})
const server = createServer(async (req, res) => {
const result = await handler.handle(req, res, {
context: { headers: req.headers }
})
if (!result.matched) {
res.statusCode = 404
res.end('No procedure matched')
}
})
server.listen(
3000,
'127.0.0.1',
() => console.log('Listening on 127.0.0.1:3000')
)
Important Changes:
- Use
OpenAPIHandler
instead ofRPCHandler
. - Learn more in OpenAPIHandler.
Accessing APIs
curl -X GET http://127.0.0.1:3000/planets
curl -X GET http://127.0.0.1:3000/planets/1
curl -X POST http://127.0.0.1:3000/planets \
-H 'Authorization: Bearer token' \
-H 'Content-Type: application/json' \
-d '{"name": "name"}'
Just a small tweak makes your oRPC API OpenAPI-compliant!
Generating OpenAPI Spec
import { OpenAPIGenerator } from '@orpc/openapi'
import { ZodToJsonSchemaConverter } from '@orpc/zod'
import { router } from './shared/planet'
const generator = new OpenAPIGenerator({
schemaConverters: [
new ZodToJsonSchemaConverter()
]
})
const spec = await generator.generate(router, {
info: {
title: 'Planet API',
version: '1.0.0'
}
})
console.log(JSON.stringify(spec, null, 2))
Run the script above to generate your OpenAPI spec.
INFO
oRPC supports a wide range of Standard Schema for OpenAPI generation. See the full list here