### 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: {}, }, ], }), ], }) ```