### Install Dependencies and Start Dev Server
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/playgrounds.md
After cloning the playground, install the necessary dependencies using npm and start the development server to run the application locally.
```bash
# Install dependencies
npm install
# Start the development server
npm run dev
```
--------------------------------
### Install dependencies
Source: https://github.com/middleapi/orpc/blob/main/CONTRIBUTING.md
Run this command to install all necessary project dependencies.
```bash
pnpm install
```
--------------------------------
### Install Publisher Helper with bun
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/helpers/publisher.md
Install the beta version of the publisher helper using bun.
```sh
bun add @orpc/publisher@beta
```
--------------------------------
### Install Publisher Helper with deno
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/helpers/publisher.md
Install the beta version of the publisher helper using deno.
```sh
deno add npm:@orpc/publisher@beta
```
--------------------------------
### Start Development Server
Source: https://github.com/middleapi/orpc/blob/main/playgrounds/next/README.md
Run this command to start the Next.js development server for the oRPC playground.
```bash
npm run dev
```
--------------------------------
### Install Publisher Helper with yarn
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/helpers/publisher.md
Install the beta version of the publisher helper using yarn.
```sh
yarn add @orpc/publisher@beta
```
--------------------------------
### Install Publisher Helper with pnpm
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/helpers/publisher.md
Install the beta version of the publisher helper using pnpm.
```sh
pnpm add @orpc/publisher@beta
```
--------------------------------
### Basic Scalar Setup with oRPC
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/openapi/scalar.md
This example demonstrates how to set up a Node.js HTTP server to serve both the OpenAPI specification and the Scalar interactive API reference UI. It configures the OpenAPI handler, generates the OpenAPI spec, and embeds the Scalar UI using its CDN.
```typescript
import { createServer } from 'node:http'
import { OpenAPIGenerator } from '@orpc/openapi'
import { OpenAPIHandler } from '@orpc/openapi/node'
import { CORSPlugin } from '@orpc/server/plugins'
import { ZodToJsonSchemaConverter } from '@orpc/zod'
const openAPIHandler = new OpenAPIHandler(router, {
plugins: [
new CORSHandlerPlugin(),
],
})
const openAPIGenerator = new OpenAPIGenerator({
schemaConverters: [
new ZodToJsonSchemaConverter(),
],
})
const server = createServer(async (req, res) => {
const { matched } = await openAPIHandler.handle(req, res, {
prefix: '/api',
})
if (matched) {
return
}
if (req.url === '/spec.json') {
const spec = await openAPIGenerator.generate(router, {
info: {
title: 'My Playground',
version: '1.0.0',
},
servers: [
{ url: '/api' }, /** Use an absolute URL in production. */
],
security: [{ bearerAuth: [] }],
components: {
securitySchemes: {
bearerAuth: {
type: 'http',
scheme: 'bearer',
},
},
},
})
res.writeHead(200, { 'Content-Type': 'application/json' })
res.end(JSON.stringify(spec))
return
}
const html = `
My Client
`
res.writeHead(200, { 'Content-Type': 'text/html' })
res.end(html)
})
server.listen(3000, () => {
console.log('Playground is available at http://localhost:3000')
})
```
--------------------------------
### Install Publisher Helper with npm
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/helpers/publisher.md
Install the beta version of the publisher helper using npm.
```sh
npm install @orpc/publisher@beta
```
--------------------------------
### Install @orpc/ratelimit
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/helpers/ratelimit.md
Install the @orpc/ratelimit package using your preferred package manager.
```sh
npm install @orpc/ratelimit@beta
```
```sh
yarn add @orpc/ratelimit@beta
```
```sh
pnpm add @orpc/ratelimit@beta
```
```sh
bun add @orpc/ratelimit@beta
```
```sh
deno add npm:@orpc/ratelimit@beta
```
--------------------------------
### Install ORPC Client with deno
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/client/client-side.md
Use this command to install the ORPC client package using deno.
```sh
deno add npm:@orpc/client@beta
```
--------------------------------
### Install ORPC Client with bun
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/client/client-side.md
Use this command to install the ORPC client package using bun.
```sh
bun add @orpc/client@beta
```
--------------------------------
### Create tRPC Base Procedures
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/migrations/from-trpc.md
This example shows the equivalent tRPC setup for creating a shared context and middleware, including a timing middleware and a protected procedure that enforces authentication.
```ts
import { initTRPC, TRPCError } from '@trpc/server'
import superjson from 'superjson'
export async function createTRPCContext(opts: { headers: Headers }) {
const session = await auth()
return {
headers: opts.headers,
session,
}
}
const t = initTRPC.context().create({
transformer: superjson,
})
export const createTRPCRouter = t.router
const timingMiddleware = t.middleware(async ({ next, path }) => {
const start = Date.now()
const result = await next()
const end = Date.now()
console.log(`[tRPC] ${path} took ${end - start}ms to execute`)
return result
})
export const publicProcedure = t.procedure.use(timingMiddleware)
export const protectedProcedure = t.procedure
.use(timingMiddleware)
.use(({ ctx, next }) => {
if (!ctx.session?.user) {
throw new TRPCError({ code: 'UNAUTHORIZED' })
}
return next({
ctx: {
session: { ...ctx.session, user: ctx.session.user },
},
})
})
```
--------------------------------
### Install and Use Published Client
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/advanced/publish-client-to-npm.md
Installs the published client package using `pnpm add` and demonstrates how to import and use the `createMyApi` function to interact with the API.
```bash
pnpm add ""
```
```typescript
import { createMyApi } from ''
const myApi = createMyApi('your-api-key')
const output = await myApi.someMethod('input')
```
--------------------------------
### Install Effect Integration (bun)
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/integrations/effect.md
Install the experimental Effect integration for oRPC and the Effect library using bun.
```sh
bun add @orpc/experimental-effect@beta effect@beta
```
--------------------------------
### Create oRPC Client
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/advanced/publish-client-to-npm.md
Sets up and exports an oRPC client using RPC Link and Contract First. This is an example and can be adapted to other link or client setups.
```typescript
import { createORPCClient } from '@orpc/client'
import { RPCLink } from '@orpc/client/fetch'
import type { RouterContractClient } from '@orpc/contract'
export function createMyApi(apiKey: string): RouterContractClient {
const link = new RPCLink({
origin: 'https://example.com',
url: '/rpc',
headers: {
'x-api-key': apiKey,
},
})
return createORPCClient(link)
}
```
--------------------------------
### Basic Procedure Contract Setup
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/contract/procedure.md
Defines a procedure contract with metadata, errors, and input/output validation using Zod. This is a foundational example for creating typed procedures.
```typescript
import { z } from 'zod'
import type { AnyMetaPlugin } from '@orpc/contract'
declare const someMeta: AnyMetaPlugin
// ---cut---
import { oc } from '@orpc/contract'
const example = oc
.meta(someMeta) // <- attach metadata
.errors({ NOT_FOUND: {} }) // <- define errors
.input(z.object({ id: z.number(), name: z.string() })) // <- input validation
.output(z.object({ id: z.number(), name: z.string() })) // <- output validation
```
--------------------------------
### Run development playground
Source: https://github.com/middleapi/orpc/blob/main/CONTRIBUTING.md
Navigate to the Next.js playground and start the development server.
```bash
cd playgrounds/next
pnpm dev
```
--------------------------------
### Install Effect Integration (deno)
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/integrations/effect.md
Install the experimental Effect integration for oRPC and the Effect library using deno.
```sh
deno add npm:@orpc/experimental-effect@beta npm:effect@beta
```
--------------------------------
### Install Pino and @orpc/pino
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/integrations/pino.md
Install the necessary packages for Pino integration using your preferred package manager.
```sh
npm install @orpc/pino@beta pino@beta
```
```sh
yarn add @orpc/pino@beta pino@beta
```
```sh
pnpm add @orpc/pino@beta pino@beta
```
```sh
bun add @orpc/pino@beta pino@beta
```
```sh
deno add npm:@orpc/pino@beta npm:pino@beta
```
--------------------------------
### Manually Define Example Metadata Plugin
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/metadata.md
Define a custom metadata plugin directly for more control over procedure types. This example creates an 'example' plugin to attach input and output examples to procedures.
```typescript
import { os } from '@orpc/server'
import z from 'zod'
// ---cut---
import type {
AnySchema,
ErrorMap,
InferSchemaInput,
InferSchemaOutput,
Meta,
MetaPlugin,
} from '@orpc/server'
interface ExampleMeta {
inputExamples?: InferSchemaInput[]
outputExamples?: InferSchemaOutput[]
}
interface ExampleMetaPlugin extends MetaPlugin {
name: 'example'
}
function exampleMeta(
incoming: ExampleMeta
): ExampleMetaPlugin {
return {
name: 'example',
apply(meta) {
const current = meta.example as ExampleMeta | undefined
return {
...meta,
example: {
...current,
...incoming,
}
}
},
}
}
function getExampleMeta(
procedureOrLazy: { '~orpc': { meta: Meta } }
): ExampleMeta | undefined {
return procedureOrLazy['~orpc'].meta.example as ExampleMeta | undefined
}
const procedure = os
.input(z.object({ name: z.string() }))
.output(z.object({ id: z.string(), name: z.string() }))
.meta(exampleMeta({
inputExamples: [{ name: 'Alice' }], // <- typesafe
outputExamples: [{ id: '1', name: 'Alice' }], // <- typesafe
}))
.handler(async ({ input }) => {
return { id: '1', name: 'Alice' }
})
```
--------------------------------
### Install ORPC Client with npm
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/client/client-side.md
Use this command to install the ORPC client package using npm.
```sh
npm install @orpc/client@beta
```
--------------------------------
### Install ORPC Client with yarn
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/client/client-side.md
Use this command to install the ORPC client package using yarn.
```sh
yarn add @orpc/client@beta
```
--------------------------------
### Example Usage of Procedure and Router Clients
Source: https://github.com/middleapi/orpc/blob/main/apps/content/learn-and-contribute/mini-orpc/server-side-client.md
Demonstrates how to create and use clients for individual procedures and entire routers with specified context.
```typescript
// Create a client for a single procedure
const procedureClient = createProcedureClient(myProcedure, {
context: { userId: '123' },
})
const result = await procedureClient({ input: 'example' })
// Create a client for an entire router
const routerClient = createRouterClient(myRouter, {
context: { userId: '123' },
})
const result = await routerClient.someProcedure({ input: 'example' })
```
--------------------------------
### Install oRPC Next.js Package
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/integrations/next.md
Install the oRPC Next.js beta package using your preferred package manager.
```sh
npm install @orpc/next@beta
```
```sh
yarn add @orpc/next@beta
```
```sh
pnpm add @orpc/next@beta
```
```sh
bun add @orpc/next@beta
```
```sh
deno add npm:@orpc/next@beta
```
--------------------------------
### Install ORPC Client with pnpm
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/client/client-side.md
Use this command to install the ORPC client package using pnpm.
```sh
pnpm add @orpc/client@beta
```
--------------------------------
### Install Effect Integration (npm)
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/integrations/effect.md
Install the experimental Effect integration for oRPC and the Effect library using npm.
```sh
npm install @orpc/experimental-effect@beta effect@beta
```
--------------------------------
### Install Effect Integration (yarn)
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/integrations/effect.md
Install the experimental Effect integration for oRPC and the Effect library using yarn.
```sh
yarn add @orpc/experimental-effect@beta effect@beta
```
--------------------------------
### Basic Routing Example
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/openapi/routing.md
Demonstrates how procedures are exposed by default (POST) and how to override this with custom methods and paths using `openapi` metadata.
```APIDOC
## Basic Routing
If you do not set OpenAPI routing metadata, a procedure is exposed as a `POST` endpoint whose path is derived from the router structure. For example:
```ts
import { os } from '@orpc/server'
import { openapi } from '@orpc/openapi'
const router = {
planet: {
list: os
.meta(openapi({ method: 'GET', path: '/planets' }))
.handler(async () => [{ id: 'earth', name: 'Earth' }]),
create: os
.handler(async () => ({})),
}
}
```
In this example, `list` is exposed as `GET /planets` because it overrides the default method and path. `create` keeps the default behavior, so it is exposed as `POST /planet/create`.
```
--------------------------------
### Install Effect Integration (pnpm)
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/integrations/effect.md
Install the experimental Effect integration for oRPC and the Effect library using pnpm.
```sh
pnpm add @orpc/experimental-effect@beta effect@beta
```
--------------------------------
### Install Evlog Packages
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/integrations/evlog.md
Install the necessary Evlog packages for your project using your preferred package manager.
```sh
npm install @orpc/evlog@beta evlog@beta
```
```sh
yarn add @orpc/evlog@beta evlog@beta
```
```sh
pnpm add @orpc/evlog@beta evlog@beta
```
```sh
bun add @orpc/evlog@beta evlog@beta
```
```sh
deno add npm:@orpc/evlog@beta npm:evlog@beta
```
--------------------------------
### Server Setup
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/plugins/batch.md
Instantiate the BatchHandlerPlugin on the server to handle incoming batch requests.
```typescript
import { BatchHandlerPlugin } from '@orpc/server/plugins'
const handler = new RPCHandler(router, {
plugins: [
new BatchHandlerPlugin(),
],
})
```
--------------------------------
### Setup OpenAPI Generator and Reference Plugin
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/plugins/openapi-reference.md
Configure the OpenAPI Generator with converters and initialize the OpenAPIReferencePlugin. This snippet demonstrates the basic setup for generating and serving the OpenAPI specification.
```typescript
import { OpenAPIGenerator } from '@orpc/openapi'
import { OpenAPIReferencePlugin } from '@orpc/openapi/plugins'
const generator = new OpenAPIGenerator({
converters: [
new ZodToJsonSchemaConverter(),
],
})
const handler = new OpenAPIHandler(router, {
plugins: [
new OpenAPIReferencePlugin({
spec: () => generator.generateSpec(router, {
info: {
title: 'ORPC Playground',
version: '1.0.0',
},
servers: [
{ url: 'https://api.example.com/v1', },
],
}),
}),
]
})
```
--------------------------------
### Install OpenTelemetry Package
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/integrations/opentelemetry.md
Install the OpenTelemetry integration package for oRPC using your preferred package manager.
```sh
npm install @orpc/opentelemetry@beta
```
```sh
yarn add @orpc/opentelemetry@beta
```
```sh
pnpm add @orpc/opentelemetry@beta
```
```sh
bun add @orpc/opentelemetry@beta
```
```sh
deno add npm:@orpc/opentelemetry@beta
```
--------------------------------
### Client Setup
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/plugins/batch.md
Instantiate the BatchLinkPlugin on the client to group outgoing requests into batches. Configure groups with conditions and context.
```typescript
import { BatchLinkPlugin } from '@orpc/client/plugins'
const link = new RPCLink({
url: '/rpc',
plugins: [
new BatchLinkPlugin({
groups: [
{
condition: () => true,
context: {},
},
],
}),
],
})
```
--------------------------------
### Configure MemoryRateLimiter
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/helpers/ratelimit.md
Example of configuring the MemoryRateLimiter with max requests and a time window.
```ts
import { MemoryRateLimiter } from '@orpc/ratelimit/memory'
const limiter = new MemoryRateLimiter({
maxRequests: 10, // Maximum requests allowed
window: 60000, // Time window in milliseconds (60 seconds)
})
```
--------------------------------
### Install TanStack Query Integration
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/integrations/tanstack-query.md
Install the TanStack Query integration package for oRPC using your preferred package manager.
```sh
npm install @orpc/tanstack-query@beta
```
```sh
yarn add @orpc/tanstack-query@beta
```
```sh
pnpm add @orpc/tanstack-query@beta
```
```sh
bun add @orpc/tanstack-query@beta
```
```sh
deno add npm:@orpc/tanstack-query@beta
```
--------------------------------
### URL Query Example
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/openapi/bracket-notation.md
Demonstrates how nested object structures can be represented in URL query strings using bracket notation.
```bash
curl 'http://example.com/api/example?name[first]=John&name[last]=Doe'
```
```json
{
"name": {
"first": "John",
"last": "Doe"
}
}
```
--------------------------------
### Upstash Publisher Setup
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/helpers/publisher.md
Initialize the UpstashPublisher using environment variables for Redis connection. Optional prefix and serializer can be configured.
```typescript
import { Redis } from '@upstash/redis'
import { UpstashPublisher } from '@orpc/publisher/upstash'
const redis = Redis.fromEnv()
const publisher = new UpstashPublisher(redis, {
prefix: 'orpc:', // Optional Redis key prefix
serializer: undefined, // Optional custom serializer
})
```
--------------------------------
### Install ORPC JSON Schema Plugin
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/plugins/smart-coercion.md
Install the beta version of the ORPC JSON Schema package using your preferred package manager.
```sh
npm install @orpc/json-schema@beta
```
```sh
yarn add @orpc/json-schema@beta
```
```sh
pnpm add @orpc/json-schema@beta
```
```sh
bun add @orpc/json-schema@beta
```
```sh
deno add npm:@orpc/json-schema@beta
```
--------------------------------
### Server Setup for Next.js API Route
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/migrations/from-trpc.md
Compares the server setup for handling requests in a Next.js API route. oRPC uses `RPCHandler`, while tRPC uses `fetchRequestHandler`.
```ts
import { RPCHandler } from '@orpc/server/fetch'
const handler = new RPCHandler(appRouter, {
interceptors: [
async ({ next, path }) => {
try {
return await next()
}
catch (error) {
console.error(`❌ oRPC failed on ${path.join('.')}: `, error)
throw error
}
}
]
})
async function handleRequest(request: Request) {
const { response } = await handler.handle(request, {
prefix: '/api/orpc',
context: await createORPCContext({ headers: request.headers })
})
return response ?? new Response('Not found', { status: 404 })
}
export const GET = handleRequest
export const POST = handleRequest
```
```ts
import { fetchRequestHandler } from '@trpc/server/adapters/fetch'
function handler(req: Request) {
return fetchRequestHandler({
endpoint: '/api/trpc',
req,
router: appRouter,
createContext: () => createTRPCContext({ headers: req.headers }),
onError: ({ path, error }) => {
console.error(
`❌ tRPC failed on ${path ?? ''}: ${error.message}`
)
}
})
}
export { handler as GET, handler as POST }
```
--------------------------------
### Prefixes
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/openapi/routing.md
Explains how to use the `prefix` option to prepend a path to a procedure or an entire router, including examples with path parameters in prefixes.
```APIDOC
## Prefixes
Define `prefix` to prepend a path to a procedure, or an entire router:
```ts
const planetBuilder = os.meta(openapi({ prefix: '/planets' }))
const listPlanets = planetBuilder
.meta(openapi({ method: 'GET', path: '/' }))
.handler(async () => [{ id: 'earth', name: 'Earth' }])
const createPlanet = planetBuilder
.handler(async () => ({}))
const router = os.meta(openapi({ prefix: '/api/v2' })).router({
planet: {
list: listPlanets,
create: createPlanet,
},
})
```
In this example, `listPlanets` is exposed as `GET /api/v2/planets/`. `createPlanet` is exposed as `POST /api/v2/planets/planet/create`.
### Path Parameters in Prefixes
Prefixes can also include path parameters, but they must be defined as required fields in the input schema.
```ts
const base = os
.meta(openapi({ prefix: '/{workspaceId}' }))
.input(z.looseObject({ workspaceId: z.string() }))
.use(({ next }, { workspaceId }) => {
console.log('Workspace ID:', workspaceId)
return next()
})
const procedure = base
.meta(openapi({ method: 'GET', path: '/planets/{id}' }))
.input(z.looseObject({ id: z.string() }))
.handler(async ({ input }) => {
console.log('Workspace ID:', input.workspaceId)
console.log('Planet ID:', input.id)
})
```
```
--------------------------------
### Configure RedisRateLimiter
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/helpers/ratelimit.md
Example of configuring the RedisRateLimiter with a Redis client and rate limit options.
```ts
import { RedisRateLimiter } from '@orpc/ratelimit/redis'
import { createClient } from 'redis'
const client = createClient({ url: 'redis://localhost:6379' })
// RedisRateLimiter lazily connects to Redis when needed.
// You can still call `client.connect()` manually, but it is optional.
await client.connect()
const limiter = new RedisRateLimiter(client, {
prefix: 'orpc:', // Optional Redis key prefix
maxRequests: 10, // Maximum requests allowed
window: 60000, // Time window in milliseconds (60 seconds)
})
```
--------------------------------
### Raw Server Output Example
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/advanced/expanding-type-support-for-openapi-link.md
Illustrates the JSON-friendly format that the server returns for Date and bigint types, which is compatible with OpenAPI.
```typescript
const rawOutput = {
date: '2025-09-01T07:24:39.000Z',
bigint: '123',
}
```
--------------------------------
### Basic RPCHandler Setup with Interceptors and Plugins
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/rpc/handler.md
Initialize RPCHandler with custom interceptors for logging and error handling, and plugins like CORSHandlerPlugin.
```typescript
const handler = new RPCHandler(router, {
interceptors: [
async ({ next, path }) => {
console.time(path.join('.'))
try {
return await next()
}
catch (err) {
console.error(`${path.join('.')}:`, err)
throw err
}
finally {
console.timeEnd(path.join('.'))
}
}
],
plugins: [
new CORSHandlerPlugin()
],
})
```
--------------------------------
### Inline Middleware Example
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/middleware.md
Demonstrates defining and using middleware inline with the `.use` method for simple middleware logic.
```typescript
const example = os
.use(async ({ context, next }) => {
// Execute logic before the handler
return next()
})
.handler(async ({ context }) => {
// Handler logic
})
```
--------------------------------
### Create Reusable Implementer Instances
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/contract/implementation.md
Create separate implementer instances for different setups, like a base setup for public procedures and another extended with authentication. This prevents reference issues and promotes reusability.
```typescript
const pub = implementer // Base setup for procedures that publish
const authed = implementer.use(requireAuth) // Extends 'pub' with authentication
const listPlanets = pub.planet.list.handler(({ input }) => {
// Your logic for listing planets without authentication
return []
})
const createPlanet = authed.planet.create.handler(({ input }) => {
// Your logic for creating planets with authentication
return { }
})
```
--------------------------------
### Client-Side OpenTelemetry Setup
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/integrations/opentelemetry.md
Instrument your oRPC client using WebTracerProvider and ORPCInstrumentation for automatic tracing in web environments.
```ts
import { WebTracerProvider } from '@opentelemetry/sdk-trace-web'
import { registerInstrumentations } from '@opentelemetry/instrumentation'
import { ORPCInstrumentation } from '@orpc/opentelemetry'
const provider = new WebTracerProvider()
provider.register()
registerInstrumentations({
instrumentations: [
new ORPCInstrumentation(), // [!code highlight]
],
})
```
--------------------------------
### Server-Side OpenTelemetry Setup
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/integrations/opentelemetry.md
Instrument your oRPC server using NodeSDK and ORPCInstrumentation for automatic tracing.
```ts
import { NodeSDK } from '@opentelemetry/sdk-node'
import { ORPCInstrumentation } from '@orpc/opentelemetry'
const sdk = new NodeSDK({
instrumentations: [
new ORPCInstrumentation(), // [!code highlight]
],
})
sdk.start()
```
--------------------------------
### Form Data Example
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/openapi/bracket-notation.md
Shows how to send nested data using bracket notation in HTTP POST requests with form data.
```bash
curl -X POST http://example.com/api/example \
-F 'name[first]=John' \
-F 'name[last]=Doe'
```
```json
{
"name": {
"first": "John",
"last": "Doe"
}
}
```
--------------------------------
### Create oRPC Base Procedures
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/migrations/from-trpc.md
Define a shared context and middleware for oRPC procedures, similar to tRPC's setup. This example includes a timing middleware and a protected procedure that checks for user authentication.
```ts
import { ORPCError, os } from '@orpc/server'
export async function createORPCContext(opts: { headers: Headers }) {
const session = await auth()
return {
headers: opts.headers,
session,
}
}
const o = os.$context>>()
const timingMiddleware = o.middleware(async ({ next, path }) => {
const start = Date.now()
try {
return await next()
}
finally {
console.log(`[oRPC] ${path} took ${Date.now() - start}ms to execute`)
}
})
export const publicProcedure = o.use(timingMiddleware)
export const protectedProcedure = publicProcedure.use(({ context, next }) => {
if (!context.session?.user) {
throw new ORPCError('UNAUTHORIZED')
}
return next({
context: {
session: { ...context.session, user: context.session.user }
}
})
})
```
--------------------------------
### Setup RetryLinkPlugin
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/plugins/retry.md
Import and initialize the RetryLinkPlugin for client-side request retries. Ensure you understand client context management for retry behavior.
```typescript
import { RetryLinkPlugin, RetryLinkPluginContext } from '@orpc/client/plugins'
interface ClientContext extends RetryLinkPluginContext {}
const link = new RPCLink({
plugins: [
new RetryLinkPlugin(),
],
})
```
--------------------------------
### Configure RPCLink with TanStack Query Operation Context
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/integrations/tanstack-query.md
Customize the HTTP method for RPC Link based on the TanStack Query operation type. This example sets 'GET' for query-like operations and 'POST' otherwise.
```typescript
import { RPCLink } from '@orpc/client/fetch'
// ---
import {
TANSTACK_QUERY_OPERATION_CONTEXT_SYMBOL,
TanstackQueryOperationContext,
} from '@orpc/tanstack-query'
interface ClientContext extends TanstackQueryOperationContext {
}
const GET_OPERATION_TYPE = new Set(['query', 'streamed', 'live', 'infinite'])
const link = new RPCLink({
method: ({ context }) => {
const operationType = context[TANSTACK_QUERY_OPERATION_CONTEXT_SYMBOL]?.type
if (operationType && GET_OPERATION_TYPE.has(operationType)) {
return 'GET'
}
return 'POST'
},
})
```
--------------------------------
### Client Setup Comparison
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/migrations/from-trpc.md
Demonstrates how to set up a typed client for making requests. oRPC uses `createORPCClient` with a `RPCLink`, while tRPC uses `createTRPCProxyClient` with `httpLink`.
```ts
import { createORPCClient, onError } from '@orpc/client'
import { RPCLink } from '@orpc/client/fetch'
import { RouterClient } from '@orpc/server'
const link = new RPCLink({
origin: 'http://localhost:3000',
url: '/api/orpc',
interceptors: [
onError((error) => {
console.error(error)
})
],
})
export const client: RouterClient = createORPCClient(link)
// ---------------- Usage ----------------
const { planets } = await client.planet.list({ cursor: 0 })
```
```ts
import { createTRPCProxyClient, httpLink } from '@trpc/client'
export const client = createTRPCProxyClient({
links: [
httpLink({
url: 'http://localhost:3000/api/trpc'
})
]
})
// ---------------- Usage ----------------
const { planets } = await client.planet.list.query({ cursor: 0 })
```
--------------------------------
### Initialize and Use oRPC Client
Source: https://github.com/middleapi/orpc/blob/main/apps/content/learn-and-contribute/mini-orpc/client-side-client.md
Demonstrates initializing the client with a link and invoking a procedure.
```ts
const link = new RPCLink({
url: `${window.location.origin}/rpc`,
})
export const orpc: RouterClient = createORPCClient(link)
const result = await orpc.someProcedure({ input: 'example' })
```
--------------------------------
### Basic Publisher and Subscriber Setup
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/helpers/publisher.md
Demonstrates setting up a MemoryPublisher and subscribing to 'something-updated' events. The handler yields received payloads, and a separate handler publishes events with an ID.
```ts
import { MemoryPublisher } from '@orpc/publisher/memory'
import { os } from '@orpc/server'
import * as z from 'zod'
// ---cut---
const publisher = new MemoryPublisher<{
'something-updated': {
id: string
}
}>()
const live = os
.handler(async function* ({ input, signal, lastEventId }) {
const iterator = publisher.subscribe('something-updated', { signal, lastEventId })
for await (const payload of iterator) {
// Handle payload here or yield directly to client
yield payload
}
})
const publish = os
.input(z.object({ id: z.string() }))
.handler(async ({ input }) => {
await publisher.publish('something-updated', { id: input.id })
})
```
--------------------------------
### Setting up Request Headers Handler Plugin
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/plugins/request-headers.md
Shows how to initialize the `RPCHandler` and include the `RequestHeadersHandlerPlugin` in the list of plugins.
```typescript
import { RequestHeadersHandlerPlugin } from '@orpc/server/plugins'
const handler = new RPCHandler(router, {
plugins: [
new RequestHeadersHandlerPlugin(),
],
})
```
--------------------------------
### Redis Publisher Setup
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/helpers/publisher.md
Configure and initialize the RedisPublisher. Ensure a Redis client is created and optionally connected. The subscriber client is a duplicate of the main client.
```typescript
import { createClient } from 'redis'
import { RedisPublisher } from '@orpc/publisher/redis'
const client = createClient({ url: 'redis://localhost:6379' })
// RedisRateLimiter lazily connects to Redis when needed.
// You can still call `client.connect()` manually, but it is optional.
await client.connect()
const publisher = new RedisPublisher(client, {
subscriber: client.duplicate(), // Redis client for subscribing to pub/sub (default: client.duplicate())
prefix: 'orpc:', // Optional Redis key prefix
serializer: undefined, // Optional custom serializer
})
```
--------------------------------
### Setup TanStack Query Utilities
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/integrations/tanstack-query.md
Create TanStack Query utilities by initializing `createTanstackQueryUtils` with your oRPC client. This enables building query options.
```ts
import { client } from './shared/planet'
// ---cut---
import { createTanstackQueryUtils } from '@orpc/tanstack-query'
const orpc = createTanstackQueryUtils(client)
orpc.planet.find.queryOptions({ input: { id: 123 } })
```
--------------------------------
### Install oRPC packages
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/migrations/from-trpc.md
Remove tRPC packages and install the equivalent oRPC packages using your preferred package manager.
```sh
npm uninstall @trpc/server @trpc/client @trpc/tanstack-react-query
npm install @orpc/server@beta @orpc/client@beta @orpc/tanstack-query@beta
```
```sh
yarn remove @trpc/server @trpc/client @trpc/tanstack-react-query
yarn add @orpc/server@beta @orpc/client@beta @orpc/tanstack-query@beta
```
```sh
pnpm remove @trpc/server @trpc/client @trpc/tanstack-react-query
pnpm add @orpc/server@beta @orpc/client@beta @orpc/tanstack-query@beta
```
```sh
bun remove @trpc/server @trpc/client @trpc/tanstack-react-query
bun add @orpc/server@beta @orpc/client@beta @orpc/tanstack-query@beta
```
```sh
deno remove npm:@trpc/server npm:@trpc/client npm:@trpc/tanstack-react-query
deno add npm:@orpc/server@beta npm:@orpc/client@beta npm:@orpc/tanstack-query@beta
```
--------------------------------
### Basic Request Validation Plugin Setup
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/plugins/request-validation.md
Import and initialize the RequestValidationLinkPlugin with your contract. This is the fundamental setup for enabling request validation.
```typescript
import { RequestValidationLinkPlugin } from '@orpc/contract/plugins'
const link = new RPCLink({
plugins: [
new RequestValidationLinkPlugin(contract),
],
})
```
--------------------------------
### Node HTTP RPC Server
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/adapters/node-http.md
Set up an RPC server using Node's built-in http module. This example demonstrates initializing the RPCHandler with plugins and interceptors, and handling incoming requests.
```typescript
import { createServer } from 'node:http' // or 'node:https' or 'node:http2'
import { RPCHandler } from '@orpc/server/node'
import { CORSHandlerPlugin } from '@orpc/server/plugins'
import { onError } from '@orpc/server'
const handler = new RPCHandler(router, {
plugins: [
new CORSHandlerPlugin()
],
interceptors: [
onError((error) => {
console.error(error)
}),
],
})
const server = createServer(async (req, res) => {
const { matched } = await handler.handle(req, res, {
prefix: '/rpc',
context: {} // Provide initial context if needed
})
if (matched) {
return
}
res.statusCode = 404
res.end('Not found')
})
server.listen(3000, '127.0.0.1', () => console.log('Listening on 127.0.0.1:3000'))
```
--------------------------------
### Compact Input Mapping for GET Request
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/openapi/input-and-output-mapping.md
Maps path and query parameters into a single input object for GET requests. Useful for simple data retrieval.
```typescript
const searchPlanets = os
.meta(openapi({ method: 'GET', path: '/planets/{id}' }))
.input(z.object({
id: z.string(),
q: z.string().optional(),
}))
.handler(async ({ input }) => {
return { id: input.id, q: input.q }
})
```
--------------------------------
### Resetting Metadata to Undefined
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/openapi/specification.md
Illustrates how setting `openapi` metadata to `undefined` resets its behavior. In this example, `tags` is reset to `undefined`, meaning no tags will be applied to the `example` procedure.
```typescript
const example = os
.meta(openapi({ tags: ['planets'] }))
.meta(openapi({ tags: undefined }))
```
--------------------------------
### Create ORPC Client Instance
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/client/client-side.md
Create a client instance for contract-first or normal approach using a link. Ensure the link is properly configured to communicate with the server.
```ts
import { createORPCClient } from '@orpc/client'
import { RouterContractClient } from '@orpc/contract'
import { RouterClient } from '@orpc/server'
// if you are following contract-first approach
const contractClient: RouterContractClient = createORPCClient(link)
// if you are following normal approach
const normalClient: RouterClient = createORPCClient(link)
```
--------------------------------
### RPC Link Transport Interceptor Example
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/rpc/link.md
Use transport interceptors to inspect or rewrite the request after input encoding and before response decoding. This example adds a unique request ID header to outgoing requests.
```typescript
const link = new RPCLink({
transportInterceptors: [
async (options) => {
const response = await options.next({
...options,
request: {
...options.request,
headers: {
...options.request.headers,
'x-request-id': crypto.randomUUID(),
},
},
})
return response
},
],
})
```
--------------------------------
### Define a GET API Endpoint with oRPC
Source: https://github.com/middleapi/orpc/blob/main/apps/content/blog/v1-announcement.md
This snippet demonstrates how to define a GET endpoint using oRPC, including middleware, input validation, error handling, and compatibility with Server Actions and regular functions.
```typescript
const getting = os
.use(dbProvider)
.use(requiredAuth)
.use(rateLimit)
.use(analytics)
.use(sentryMonitoring)
.use(retry({ times: 3 }))
.route({ method: 'GET', path: '/getting/{id}' })
.input(z.object({ id: z.string() }))
.use(canGetting, input => input.id)
.errors({
SOME_TYPE_SAFE_ERROR: {
data: z.object({ something: z.string() })
}
})
.handler(async ({ input, errors, context }) => {
// do something
})
.actionable() // server action compatible
.callable() // regular function compatible
```
--------------------------------
### Initialize OpenAPILink
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/openapi/link.md
Instantiate `OpenAPILink` with contract details, origin, URL, and optional configurations for headers, interceptors, plugins, and a custom fetch adapter. This setup is crucial for defining how the link interacts with the target OpenAPI server.
```typescript
const link = new OpenAPILink(contract, {
origin: 'https://api.example.com',
url: '/api',
headers: ({ context }) => ({
authorization: context?.token ? `Bearer ${context.token}` : undefined,
}),
interceptors: [
async ({ next, path }) => {
console.time(path.join('.'))
try {
return await next()
}
finally {
console.timeEnd(path.join('.'))
}
},
],
plugins: [
new RetryAfterLinkPlugin(),
],
fetch: (request, init) => { // <- only available in fetch adapter
return globalThis.fetch(request, {
...init,
credentials: 'include', // Include cookies on cross-origin requests
})
},
})
```
--------------------------------
### RPC Link Fetch Interceptor Example
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/rpc/link.md
Use fetch interceptors, specific to the fetch adapter, to access the final URL and RequestInit right before the fetch call. This example includes the 'credentials: include' option in the fetch request.
```typescript
const link = new RPCLink({
fetchInterceptors: [
async (options) => {
const response = await options.next({
...options,
init: {
...options.init,
credentials: 'include',
},
})
return response
},
],
})
```
--------------------------------
### RPC Link Interceptor Example
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/rpc/link.md
Use general interceptors to observe or change all stages of an RPC request, including input encoding, transport, and response decoding. This example logs the request path, execution time, and errors.
```typescript
const link = new RPCLink({
interceptors: [
async ({ next, path, input }) => {
console.time(path.join('.'))
try {
const output = await next()
return output
}
catch (err) {
console.error(`${path.join('.')}:`, err)
throw err
}
finally {
console.timeEnd(path.join('.'))
}
},
],
})
```
--------------------------------
### Fetch API Integration with Runtimes
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/adapters/fetch-api.md
Examples of how to integrate the Fetch API handler with different server runtimes. Choose the snippet that matches your deployment environment.
```ts
Bun.serve({
fetch,
})
```
```ts
export default {
fetch,
}
```
```ts
Deno.serve(fetch)
```
```ts
import { handle } from 'hono/aws-lambda'
export const handler = handle({ fetch })
```
--------------------------------
### WebSocket Server with ws Adapter
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/adapters/websocket.md
Set up a WebSocket server using the 'ws' library and integrate oRPC's RPCHandler for handling connections and messages. Provides an example of upgrading incoming WebSocket connections and setting up per-call context.
```typescript
import { WebSocketServer } from 'ws'
import { RPCHandler } from '@orpc/server/websocket'
import { onError } from '@orpc/server'
const handler = new RPCHandler(router, {
interceptors: [
onError((error) => {
console.error(error)
}),
],
})
const wss = new WebSocketServer({ port: 8080 })
wss.on('connection', (ws) => {
handler.upgrade(ws, {
/**
* Provide initial context if needed. The context can be an async function
* that receives the per-call request as its first argument, and is **not**
* related to the initial WebSocket upgrade request.
*/
context: request => ({}),
})
})
```
--------------------------------
### Using RPCHandler with Fetch Adapter
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/rpc/handler.md
Example of how to integrate RPCHandler with the fetch adapter for handling incoming requests, including setting a request prefix and initial context.
```typescript
export async function fetch(request: Request) {
const { response } = await handler.fetch(request, {
prefix: '/rpc',
context: {} // <- provide initial context if needed
})
return response ?? new Response('Not Found', { status: 404 })
```
--------------------------------
### Configure CloudflareRateLimiter
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/helpers/ratelimit.md
Example of configuring the CloudflareRateLimiter using a Cloudflare Workers Rate Limiting binding.
```ts
import { CloudflareRateLimiter } from '@orpc/ratelimit/cloudflare'
export default {
async fetch(request, env) {
// env.MY_RATE_LIMITER is a Cloudflare Workers Rate Limiting binding
// https://developers.cloudflare.com/workers/runtime-apis/bindings/rate-limit/
const limiter = new CloudflareRateLimiter(env.MY_RATE_LIMITER, {
prefix: 'orpc:', // Optional key prefix
})
}
}
```
--------------------------------
### Setup Body Compression Plugin in RPCHandler
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/plugins/body-compression.md
Add the BodyCompressionHandlerPlugin to the plugins array when initializing the RPCHandler.
```typescript
const handler = new RPCHandler(router, {
plugins: [
new BodyCompressionHandlerPlugin(),
],
})
```
--------------------------------
### Configure Server-side RPCHandler
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/adapters/message-port.md
Sets up the RPCHandler on the server port, including error handling and context provision. The serverPort must be started after configuration.
```typescript
import { RPCHandler } from '@orpc/server/message-port'
import { onError } from '@orpc/server'
const handler = new RPCHandler(router, {
interceptors: [
onError((error) => {
console.error(error)
}),
],
})
handler.upgrade(serverPort, {
/**
* Provide initial context if needed. The context can be an async function
* that receives the per-call request as its first argument, and is **not**
* related to the initial upgrade request.
*/
context: request => ({}),
})
serverPort.start()
```
--------------------------------
### Applying Middleware
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/procedure.md
Demonstrates how to apply middleware using the .use method, including both pre-defined middleware and inline middleware functions.
```typescript
const aMiddleware = os.middleware(async ({ context, next }) => next())
const example = os
.use(aMiddleware) // Apply middleware
.use(async ({ context, next }) => next()) // Inline middleware
.handler(async ({ context }) => { /* logic */ })
```
--------------------------------
### Customize Dedupe Filter
Source: https://github.com/middleapi/orpc/blob/main/apps/content/docs/plugins/dedupe.md
Customize the DedupeLinkPlugin to only deduplicate GET requests by providing a filter function.
```typescript
const link = new RPCLink({
plugins: [
new DedupeLinkPlugin({
filter: ({ request }) => request.method === 'GET',
groups: [
{
condition: () => true,
context: {},
},
],
}),
],
})
```