Expanding Type Support for OpenAPI Link
This guide will show you how to extend OpenAPILink to support additional data types beyond JSON's native capabilities using the Response Validation Plugin.
How It Works
To enable this functionality, you need to extend your output and error schemas with proper coercion logic.
Why? OpenAPI response data only represents JSON's native capabilities. We use schema coercion logic in contract's schemas to convert the data to the desired type.
WARNING
Beyond JSON limitations, outputs containing Blob
or File
types (outside the root level) also face Bracket Notation limitations.
const contract = oc.output(z.object({
date: z.coerce.date(),
bigint: z.coerce.bigint(),
}))
const procedure = implement(contract).handler(() => ({
date: new Date(),
bigint: 123n,
}))
On the client side, you'll receive the output like this:
const beforeValidation = {
date: '2025-09-01T07:24:39.000Z',
bigint: '123'
}
Since your output schema contains coercion logic, the Response Validation Plugin will convert the data to the desired type after validation.
const afterValidation = {
date: new Date('2025-09-01T07:24:39.000Z'),
bigint: 123n
}
WARNING
To support more types than those in OpenAPI Handler, you must first extend the OpenAPI JSON Serializer first.
Setup
After understanding how it works and expanding schemas with coercion logic, you only need to set up the Response Validation Plugin and remove the JsonifiedClient
wrapper.
import type { ContractRouterClient } from '@orpc/contract'
import { createORPCClient } from '@orpc/client'
import { OpenAPILink } from '@orpc/openapi-client/fetch'
import { ResponseValidationPlugin } from '@orpc/contract/plugins'
const link = new OpenAPILink(contract, {
url: 'http://localhost:3000/api',
plugins: [
+ new ResponseValidationPlugin(contract),
]
})
-const client: JsonifiedClient<ContractRouterClient<typeof contract>> = createORPCClient(link)
+const client: ContractRouterClient<typeof contract> = createORPCClient(link)