Client-Side Clients
Client-side clients call procedures remotely, in a different process or on a different machine. They are useful in frontend applications, mobile apps, or any setup where the client and server run in different environments.
Installation
npm install @orpc/client@betayarn add @orpc/client@betapnpm add @orpc/client@betabun add @orpc/client@betadeno add npm:@orpc/client@betaCreating a Client
To create a client, first set up a link that defines how the client communicates with the server. This can be an RPC Link, an OpenAPI Link, or any custom link. Then create a client for your router or contract using createORPCClient.
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<typeof contract> = createORPCClient(link)
// if you are following normal approach
const normalClient: RouterClient<typeof router> = createORPCClient(link)TIP
You can export RouterClient<typeof router> or RouterContractClient<typeof contract> from the server to avoid importing the contract or router in the client.
Calling Procedures
Once your client is set up, you can call your procedures as if they were local functions.
const pong = await client.ping()
client.ping
Client Context
Client context lets you pass values with each call, such as auth tokens or cache hints.
interface ClientContext {
token?: string
}
// if you are following contract-first approach
const client: RouterContractClient<typeof contract, ClientContext> = createORPCClient(link)
// if you are following normal approach
const client: RouterClient<typeof router, ClientContext> = createORPCClient(link)
const output = await client.someProcedure(input, {
context: {
token: 'abc123',
},
})Interceptors
Interceptors let you wrap client calls. They are similar to interceptors in links, but are more typesafe because the exact input, output, and error types of each client are known. You can provide per-client interceptors with scoped.
import { isInferableError, safe } from '@orpc/client'
const client: RouterClient<typeof router, ClientContext> = createORPCClient(link, {
interceptors: [
async ({ context, path, next }) => {
const [error, data] = await safe(next())
if (error) {
if (isInferableError(error)) {
// handle typesafe errors
}
throw error
}
return data
}
],
scoped: {
planet: {
find: {
interceptors: [ // <- these interceptors only apply to client.planet.find
async ({ context, path, next }) => {
return next()
}
]
}
}
}
})INFO
You can use safe and isInferableError together for typesafe error handling in interceptors.
Merging Clients
In oRPC, a client is just an object-like structure. To merge multiple clients, assign each client to a property on a new object:
const clientA: RouterClient<typeof routerA> = createORPCClient(linkA)
const clientB: RouterClient<typeof routerB> = createORPCClient(linkB)
const clientC: RouterClient<typeof routerC> = createORPCClient(linkC)
export const orpc = {
a: clientA,
b: clientB,
c: clientC,
}Utilities
INFO
These utilities can also be used for server-side clients and are not specific to client-side clients.
Infer Client Inputs
Infers input types for each procedure in a client.
import type { InferClientInputs } from '@orpc/client'
type Inputs = InferClientInputs<typeof client>
type FindPlanetInput = Inputs['planet']['find']Infer Client Body Inputs
Infers body input types for each procedure in a client. If an endpoint's input includes { body: ... }, only the body portion is extracted. Otherwise, the entire input type is used.
import type { InferClientBodyInputs } from '@orpc/client'
type BodyInputs = InferClientBodyInputs<typeof client>
type FindPlanetBodyInput = BodyInputs['planet']['find']Infer Client Outputs
Infers output types for each procedure in a client.
import type { InferClientOutputs } from '@orpc/client'
type Outputs = InferClientOutputs<typeof client>
type FindPlanetOutput = Outputs['planet']['find']Infer Client Body Outputs
Infers body output types for each procedure in a client. If an endpoint's output includes { body: ... }, only the body portion is extracted. Otherwise, the entire output type is used.
import type { InferClientBodyOutputs } from '@orpc/client'
type BodyOutputs = InferClientBodyOutputs<typeof client>
type FindPlanetBodyOutput = BodyOutputs['planet']['find']Infer Client Errors
Infers the errors each procedure in a client can throw when using type-safe error handling.
import type { InferClientErrors } from '@orpc/client'
type Errors = InferClientErrors<typeof client>
type FindPlanetError = Errors['planet']['find']Infer Client Error
Infers all possible errors the entire client can throw. This is useful with type-safe error handling.
import type { InferClientError } from '@orpc/client'
type ClientError = InferClientError<typeof client>Infer Client Context
Infers the client context type from a client.
import type { InferClientContext } from '@orpc/client'
type Context = InferClientContext<typeof client>
