Skip to content

Router Contract

Router contracts define the shape of a router without including any business logic. Use them for documentation, testing, and keeping multiple implementations of the same router aligned.

INFO

A standalone procedure contract is also a router contract, so you can use the same features with individual procedure contracts.

Overview

Define a router contract as a plain JavaScript object where each key maps to a procedure contract:

ts
import { 
oc
} from '@orpc/contract'
const
ping
=
oc
.
output
(
z
.
string
())
const
pong
=
oc
.
output
(
z
.
string
())
export const
router
= {
ping
,
pong
,
nested
: {
ping
,
pong
}
}

WARNING

For compatibility, do not use these router keys: then, bind, valueOf, toString, toJSON.

Extending Router

You can extend a router contract with shared configuration, such as attaching metadata to every procedure:

ts
const router = oc.meta(requireAuthMeta).router({
  ping,
  pong,
  nested: {
    ping,
    pong,
  }
})

Router to Contract

A normal router can be used as a contract router as long as it does not include a lazy router. If necessary, use unlazyRouter to fully resolve it and make it contract-compatible.

ts
import { unlazyRouter } from '@orpc/server'

const compatibleContract = await unlazyRouter(router)

Safely Importing Router on the Client

Sometimes you need to import the contract on the client, for example when using OpenAPI Link. If you derive the contract from a router, importing it directly can be heavy and may expose internal logic. To avoid this, follow the steps below to safely minify and export the contract.

  1. Minify the Contract Router and Export to JSON

    ts
    import fs from 'node:fs'
    import { unlazyRouter } from '@orpc/server'
    import { minifyRouterContract } from '@orpc/contract'
    
    const compatibleContract = await unlazyRouter(router)
    const minifiedRouter = minifyRouterContract(compatibleContract)
    
    fs.writeFileSync('./contract.json', JSON.stringify(minifiedRouter))

    INFO

    minifyRouterContract preserves only the metadata needed by the client; all other data is stripped out.

  2. Import the Contract JSON on the Client Side

    ts
    import contract from './contract.json'
    
    const link = new OpenAPILink(contract as typeof router)

    INFO

    Cast contract to typeof router to preserve type safety, since standard schema types cannot be serialized to JSON and must be cast manually.

Utilities

INFO

A standalone procedure contract is also a router contract, so these utilities work with individual procedure contracts too.

Infer Router Contract Inputs

Infers the input type of each procedure contract in a router contract.

ts
import type { 
InferRouterContractInputs
} from '@orpc/contract'
export type
Inputs
=
InferRouterContractInputs
<typeof
contract
>
type
FindPlanetInput
=
Inputs
['planet']['find']

Infer Router Contract Outputs

Infers the output type of each procedure contract in a router contract.

ts
import type { 
InferRouterContractOutputs
} from '@orpc/contract'
export type
Outputs
=
InferRouterContractOutputs
<typeof
contract
>
type
FindPlanetOutput
=
Outputs
['planet']['find']

Infer Router Contract Error Map

Collects the error maps from every procedure contract in a router contract into a single type.

ts
import type { 
InferRouterContractErrorMap
} from '@orpc/contract'
export type
ErrorMap
=
InferRouterContractErrorMap
<typeof
contract
>

Infer Router Contract Errors

Infers the throwable errors each procedure contract in a router contract can describe.

ts
import type { 
InferRouterContractErrors
} from '@orpc/contract'
export type
Errors
=
InferRouterContractErrors
<typeof
contract
>
type
FindPlanetError
=
Errors
['planet']['find']

Infer Router Contract Error

Infers all possible throwable errors the entire router contract can describe. This is useful when you want a single type for contract-wide error handling.

ts
import type { 
InferRouterContractError
} from '@orpc/contract'
export type
ContractError
=
InferRouterContractError
<typeof
contract
>

Released under the MIT License.