訂閱 / WebSocket
使用訂閱
提示
- 如要取得全端堆疊範例,請參閱 /examples/next-prisma-starter-websockets。
- 有關 Node.js 的基本範例,請參閱 /examples/standalone-server。
新增訂閱程序
server/router.tstsx
import { EventEmitter } from 'events';import { initTRPC } from '@trpc/server';import { observable } from '@trpc/server/observable';import { z } from 'zod';// create a global event emitter (could be replaced by redis, etc)const ee = new EventEmitter();const t = initTRPC.create();export const appRouter = t.router({onAdd: t.procedure.subscription(() => {// return an `observable` with a callback which is triggered immediatelyreturn observable<Post>((emit) => {const onAdd = (data: Post) => {// emit data to clientemit.next(data);};// trigger `onAdd()` when `add` is triggered in our event emitteree.on('add', onAdd);// unsubscribe function when client disconnects or stops subscribingreturn () => {ee.off('add', onAdd);};});}),add: t.procedure.input(z.object({id: z.string().uuid().optional(),text: z.string().min(1),}),).mutation(async (opts) => {const post = { ...opts.input }; /* [..] add to db */ee.emit('add', post);return post;}),});
server/router.tstsx
import { EventEmitter } from 'events';import { initTRPC } from '@trpc/server';import { observable } from '@trpc/server/observable';import { z } from 'zod';// create a global event emitter (could be replaced by redis, etc)const ee = new EventEmitter();const t = initTRPC.create();export const appRouter = t.router({onAdd: t.procedure.subscription(() => {// return an `observable` with a callback which is triggered immediatelyreturn observable<Post>((emit) => {const onAdd = (data: Post) => {// emit data to clientemit.next(data);};// trigger `onAdd()` when `add` is triggered in our event emitteree.on('add', onAdd);// unsubscribe function when client disconnects or stops subscribingreturn () => {ee.off('add', onAdd);};});}),add: t.procedure.input(z.object({id: z.string().uuid().optional(),text: z.string().min(1),}),).mutation(async (opts) => {const post = { ...opts.input }; /* [..] add to db */ee.emit('add', post);return post;}),});
建立 WebSocket 伺服器
bash
yarn add ws
bash
yarn add ws
server/wsServer.tsts
import { applyWSSHandler } from '@trpc/server/adapters/ws';import ws from 'ws';import { appRouter } from './routers/app';import { createContext } from './trpc';const wss = new ws.Server({port: 3001,});const handler = applyWSSHandler({ wss, router: appRouter, createContext });wss.on('connection', (ws) => {console.log(`➕➕ Connection (${wss.clients.size})`);ws.once('close', () => {console.log(`➖➖ Connection (${wss.clients.size})`);});});console.log('✅ WebSocket Server listening on ws://localhost:3001');process.on('SIGTERM', () => {console.log('SIGTERM');handler.broadcastReconnectNotification();wss.close();});
server/wsServer.tsts
import { applyWSSHandler } from '@trpc/server/adapters/ws';import ws from 'ws';import { appRouter } from './routers/app';import { createContext } from './trpc';const wss = new ws.Server({port: 3001,});const handler = applyWSSHandler({ wss, router: appRouter, createContext });wss.on('connection', (ws) => {console.log(`➕➕ Connection (${wss.clients.size})`);ws.once('close', () => {console.log(`➖➖ Connection (${wss.clients.size})`);});});console.log('✅ WebSocket Server listening on ws://localhost:3001');process.on('SIGTERM', () => {console.log('SIGTERM');handler.broadcastReconnectNotification();wss.close();});
設定 TRPCClient
以使用 WebSocket
提示
您可以使用 連結 將查詢和/或變更路由至 HTTP 傳輸,以及透過 WebSocket 訂閱。
client.tstsx
import { createTRPCClient, createWSClient, wsLink } from '@trpc/client';import type { AppRouter } from '../path/to/server/trpc';// create persistent WebSocket connectionconst wsClient = createWSClient({url: `ws://localhost:3001`,});// configure TRPCClient to use WebSockets transportconst client = createTRPCClient<AppRouter>({links: [wsLink({client: wsClient,}),],});
client.tstsx
import { createTRPCClient, createWSClient, wsLink } from '@trpc/client';import type { AppRouter } from '../path/to/server/trpc';// create persistent WebSocket connectionconst wsClient = createWSClient({url: `ws://localhost:3001`,});// configure TRPCClient to use WebSockets transportconst client = createTRPCClient<AppRouter>({links: [wsLink({client: wsClient,}),],});
使用 React
請參閱 /examples/next-prisma-starter-websockets。
WebSocket RPC 規範
您可以深入探討 TypeScript 定義以閱讀更多詳細資訊
query
/ mutation
要求
ts
{id: number | string;jsonrpc?: '2.0'; // optionalmethod: 'query' | 'mutation';params: {path: string;input?: unknown; // <-- pass input of procedure, serialized by transformer};}
ts
{id: number | string;jsonrpc?: '2.0'; // optionalmethod: 'query' | 'mutation';params: {path: string;input?: unknown; // <-- pass input of procedure, serialized by transformer};}
回應
... 如下方所示,或為錯誤。
ts
{id: number | string;jsonrpc?: '2.0'; // only defined if included in requestresult: {type: 'data'; // always 'data' for mutation / queriesdata: TOutput; // output from procedure}}
ts
{id: number | string;jsonrpc?: '2.0'; // only defined if included in requestresult: {type: 'data'; // always 'data' for mutation / queriesdata: TOutput; // output from procedure}}
subscription
/ subscription.stop
開始訂閱
ts
{id: number | string;jsonrpc?: '2.0';method: 'subscription';params: {path: string;input?: unknown; // <-- pass input of procedure, serialized by transformer};}
ts
{id: number | string;jsonrpc?: '2.0';method: 'subscription';params: {path: string;input?: unknown; // <-- pass input of procedure, serialized by transformer};}
若要取消訂閱,請呼叫 subscription.stop
ts
{id: number | string; // <-- id of your created subscriptionjsonrpc?: '2.0';method: 'subscription.stop';}
ts
{id: number | string; // <-- id of your created subscriptionjsonrpc?: '2.0';method: 'subscription.stop';}
訂閱回應外型
... 如下方所示,或為錯誤。
ts
{id: number | string;jsonrpc?: '2.0';result: (| {type: 'data';data: TData; // subscription emitted data}| {type: 'started'; // subscription started}| {type: 'stopped'; // subscription stopped})}
ts
{id: number | string;jsonrpc?: '2.0';result: (| {type: 'data';data: TData; // subscription emitted data}| {type: 'started'; // subscription started}| {type: 'stopped'; // subscription stopped})}
錯誤
請參閱 https://www.jsonrpc.org/specification#error_object 或 錯誤格式化。
伺服器至用戶端通知
{ id: null, type: 'reconnect' }
在關閉伺服器之前,通知用戶端重新連線。由 wssHandler.broadcastReconnectNotification()
呼叫。