Skip to content

Server-Side Clients

Server-side clients call procedures locally, within the same process. They are useful in microservices, serverless functions, or any setup where the caller and procedures run in the same environment.

One-Off Calls

Use call when you need to invoke a single procedure without creating a client instance.

ts
import { 
call
,
os
} from '@orpc/server'
const
result
= await
call
(
exampleProcedure
, 'input', {
context
: {} // <- provide initial context if needed
})

Router Clients

Use createRouterClient to create a client for your router. This is useful when you want to call multiple procedures.

ts
import { 
createRouterClient
} from '@orpc/server'
const
client
=
createRouterClient
(
router
, {
context
: {}, // <- provide initial context if needed, can be async function
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
('.'))
} } ] }) const
result
= await
client
.
ping
()

Client Context

Client context is passed with each call. Use it to switch between contexts, such as different users or tenants, without creating multiple client instances.

ts
interface ClientContext {
  
cache
?: boolean
} const
client
=
createRouterClient
(
router
, {
context
: ({
cache
}: ClientContext) => {
if (
cache
) {
return {} // <- context when cache enabled } return {} } }) const
result
= await
client
.
ping
(
undefined
, {
context
: {
cache
: true } })

Interceptors

Interceptors let you observe or modify an entire call. Common use cases include logging, error handling, and metrics collection.

ts
const client = createRouterClient(router, {
  interceptors: [
    async ({ next, path, context }) => {
      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('.'))
      }
    }
  ]
})

.callable extension

Import @orpc/server/extensions/callable from a module that always runs during initialization, such as the file where you define your base builder or create your server. This adds a .callable method to the decorated procedure, allowing you to call it directly like a regular function while still using it as a regular procedure.

ts
const ping = base
  .input(z.object({ name: z.string(), }))
  .handler(async ({ input }) => `Hello ${input.name}!`)
  .callable({
    context: async () => ({}), // <- provide initial context if needed, can be async function
    interceptors: [], // <- client interceptors
  })

const router = {
  ping, // <- still use it as a regular procedure
}

const message = await ping({ name: 'World' }) // <- or call it directly
ts
import '@orpc/server/extensions/callable'

import { os } from '@orpc/server'

export const base = os

Lifecycle

TODO: add lifecycle diagram

Released under the MIT License.