RPC JSON Serializer
This serializer handles JSON payloads for the RPC Protocol and supports native data types.
Extending Native Data Types
Extend native types by creating your own StandardRPCCustomJsonSerializer and adding it to the customJsonSerializers option.
Define Your Custom Serializer
tsimport type { StandardRPCCustomJsonSerializer } from '@orpc/client/standard' import * aszfrom 'zod' export classUser{ constructor( public readonlyid: string, public readonlyname: string, public readonlyemail: string, public readonlyage: number, ) {}toJSON() { return {id: this.id,name: this.name,email: this.email,age: this.age, } } } constUserSchema=z.object({id:z.string(),name:z.string(),email:z.string(),age:z.number(), }) export constuserSerializer: StandardRPCCustomJsonSerializer = {type: 21,condition:data=>datainstanceofUser,serialize:data=>data.toJSON(),deserialize: (data) => { const {id,name,email,age} =UserSchema.parse(data) return newUser(id,name,email,age) }, }WARNING
Ensure the
typeis unique and greater than20to avoid conflicts with built-in types in the future.WARNING
deserializereceives untrusted input. A malicious client controlsmetaand can point anytypeat any JSON value, so never assumedeserializereceives whatserializeproduced. Validate the value and throw when it does not match. Built-in types do the same, and RPC Handler turns these errors into aBAD_REQUESTresponse.Use Your Custom Serializer
tsconsthandler= newRPCHandler(router, {customJsonSerializers: [userSerializer], }) constlink= newRPCLink({url: 'https://example.com/rpc',customJsonSerializers: [userSerializer], })
Overriding Built-in Types
You can override built-in types by matching their type with the built-in types.
For example, oRPC represents undefined only in array items and ignores it in objects. To override this behavior:
import { StandardRPCCustomJsonSerializer } from '@orpc/client/standard'
export const undefinedSerializer: StandardRPCCustomJsonSerializer = {
type: 3, // Match the built-in undefined type.
condition: data => data === undefined,
serialize: data => null, // JSON cannot represent undefined, so use null.
deserialize: data => undefined,
}A custom serializer that matches a built-in type fully replaces it: the built-in deserialize no longer runs on that value, so your deserialize must validate the input itself.
