Getting Started
oRPC (OpenAPI Remote Procedure Call) combines RPC (Remote Procedure Call) with OpenAPI, allowing you to define and call remote (or local) procedures through a type-safe API while adhering to the OpenAPI specification.
oRPC simplifies RPC service definition, making it easy to build scalable applications, from simple scripts to complex microservices.
This guide covers the basics: defining procedures, handling errors, and integrating with popular frameworks.
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
yarn add @orpc/server@latest @orpc/client@latest
pnpm add @orpc/server@latest @orpc/client@latest
bun add @orpc/server@latest @orpc/client@latest
deno add npm:@orpc/server@latest npm:@orpc/client@latest
Define App Router
We'll use Zod for schema validation (optional, any standard schema is supported).
import type { IncomingHttpHeaders } from 'node:http'
import { ORPCError, os } from '@orpc/server'
import * as z from 'zod'
const PlanetSchema = z.object({
id: z.number().int().min(1),
name: z.string(),
description: z.string().optional(),
})
export const listPlanet = os
.input(
z.object({
limit: z.number().int().min(1).max(100).optional(),
cursor: z.number().int().min(0).default(0),
}),
)
.handler(async ({ input }) => {
// your list code here
return [{ id: 1, name: 'name' }]
})
export const findPlanet = os
.input(PlanetSchema.pick({ id: true }))
.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')
})
.input(PlanetSchema.omit({ id: true }))
.handler(async ({ input, context }) => {
// your create code here
return { id: 1, name: 'name' }
})
export const router = {
planet: {
list: listPlanet,
find: findPlanet,
create: createPlanet
}
}
Create Server
Using Node.js as the server runtime, but oRPC also supports other runtimes like Bun, Deno, Cloudflare Workers, etc.
import { createServer } from 'node:http'
import { RPCHandler } from '@orpc/server/node'
import { CORSPlugin } from '@orpc/server/plugins'
const handler = new RPCHandler(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')
)
Learn more about RPCHandler.
Create Client
import type { RouterClient } from '@orpc/server'
import { createORPCClient } from '@orpc/client'
import { RPCLink } from '@orpc/client/fetch'
const link = new RPCLink({
url: 'http://127.0.0.1:3000',
headers: { Authorization: 'Bearer token' },
})
export const orpc: RouterClient<typeof router> = createORPCClient(link)
Supports both client-side clients and server-side clients.
Call Procedure
End-to-end type-safety and auto-completion out of the box.
const planet = await orpc.planet.find({ id: 1 })
orpc.planet.create
Next Steps
This guide introduced the RPC aspects of oRPC. To explore OpenAPI integration, visit the OpenAPI Guide.