WebSocket Adapters
oRPC supports WebSockets for low-latency, full-duplex communication between clients and servers.
Server Adapters
| Adapter | Target |
|---|---|
websocket | MDN WebSocket API, ws |
crossws | crossws |
ts
import { WebSocketServer } from 'ws'
import { RPCHandler } from '@orpc/server/websocket'
import { onError } from '@orpc/server'
const handler = new RPCHandler(router, {
interceptors: [
onError((error) => {
console.error(error)
}),
],
})
const wss = new WebSocketServer({ port: 8080 })
wss.on('connection', (ws) => {
handler.upgrade(ws, {
/**
* Provide initial context if needed. The context can be an async function
* that receives the per-call request as its first argument, and is **not**
* related to the initial WebSocket upgrade request.
*/
context: request => ({}),
})
})ts
import { createServer } from 'node:http'
import { experimental_RPCHandler as RPCHandler } from '@orpc/server/crossws'
import { onError } from '@orpc/server'
// any crossws adapter is supported
import crossws from 'crossws/adapters/node'
const handler = new RPCHandler(router, {
interceptors: [
onError((error) => {
console.error(error)
}),
],
})
const ws = crossws({
hooks: {
message: (peer, message) => {
handler.message(peer, message, {
/**
* Provide initial context if needed. The context can be an async function
* that receives the per-call request as its first argument, and is **not**
* related to the initial WebSocket upgrade request.
*/
context: request => ({}),
})
},
close: (peer) => {
handler.close(peer)
},
},
})
const server = createServer((req, res) => {
res.end(`Hello World`)
}).listen(3000)
server.on('upgrade', (req, socket, head) => {
if (req.headers.upgrade === 'websocket') {
ws.handleUpgrade(req, socket, head)
}
})ts
import { RPCHandler } from '@orpc/server/websocket'
import { onError } from '@orpc/server'
const handler = new RPCHandler(router, {
interceptors: [
onError((error) => {
console.error(error)
}),
],
})
Deno.serve((req) => {
if (req.headers.get('upgrade') !== 'websocket') {
return new Response(null, { status: 501 })
}
const { socket, response } = Deno.upgradeWebSocket(req)
handler.upgrade(socket, {
/**
* Provide initial context if needed. The context can be an async function
* that receives the per-call request as its first argument, and is **not**
* related to the initial WebSocket upgrade request.
*/
context: request => ({}),
})
return response
})ts
import { RPCHandler } from '@orpc/server/websocket'
import { onError } from '@orpc/server'
const handler = new RPCHandler(router, {
interceptors: [
onError((error) => {
console.error(error)
}),
],
})
export class ChatRoom extends DurableObject {
async fetch(): Promise<Response> {
const { '0': client, '1': server } = new WebSocketPair()
this.ctx.acceptWebSocket(server)
return new Response(null, {
status: 101,
webSocket: client,
})
}
async webSocketMessage(ws: WebSocket, message: string | ArrayBuffer): Promise<void> {
await handler.message(ws, message, {
/**
* Provide initial context if needed. The context can be an async function
* that receives the per-call request as its first argument, and is **not**
* related to the initial WebSocket upgrade request.
*/
context: request => ({}),
})
}
async webSocketClose(ws: WebSocket): Promise<void> {
handler.close(ws)
}
}Client Adapters
| Adapter | Target |
|---|---|
websocket | MDN WebSocket API |
ts
import { RPCLink } from '@orpc/client/websocket'
const link = new RPCLink({
connect: info => new WebSocket('ws://localhost:3000'),
/**
* Whether to connect immediately on initialization, instead of waiting
* for the first call. Reduces latency for the first request.
*
* @default false
*/
connectOnInit: true,
/**
* Optional headers to attach to each per-call request.
* These can be accessed in the server context or via the Request Headers Plugin.
*/
headers: () => ({})
})INFO
The examples above only show how to configure the link. For examples of creating a typesafe client, see RPC Link.
Auto Reconnect
The client adapter has built-in support for reconnecting when the connection is lost. You can configure reconnect behavior with the reconnect option when creating the link.
ts
const link = new RPCLink({
reconnect: {
/**
* Whether to automatically reconnect when the connection is lost.
*
* @default false
*/
enabled: true,
/**
* Delay before a (re)connect attempt, in milliseconds.
*
* @default info => info.attempt === 1 ? 0 : 2_000
*/
delay: info => info.attempt === 1 ? 0 : 2_000,
/**
* Maximum number of consecutive failed attempts before giving up.
* When exceeded, `getConnectedPeer` throws instead of retrying.
* Should greater than 1
*
* @default Infinity
*/
maxAttempt: Infinity,
onClose: {
/**
* Whether to proactively reconnect right after the socket closes,
* rather than waiting for the next call to trigger reconnection.
* Reduces latency for the next request.
*
* @default false
*/
enabled: false,
/**
* Delay before reconnecting after the socket closes, in milliseconds.
*
* @default 0
*/
delay: 0
}
}
})
