使用 TypeBox 作為通訊協定的單一事實來源
處理跨平台的通訊協定時,最痛苦的就是要手動同步不同語言的型別定義。一旦後端改了欄位,前端或行動端沒跟上,程式碼就會在執行時悄悄崩潰,這種手動維護多套 Schema 的方式既低效又容易出錯。
我們選擇使用 TypeBox 這個 TypeScript-first 的 Schema 函式庫來定義 Gateway WebSocket 協定(包含握手、請求/回應、伺服器事件)。透過這個單一事實來源,我們可以自動驅動執行時驗證、匯出 JSON Schema,甚至為 macOS App 生成 Swift 程式碼。
需要準備的東西
Section titled “需要準備的東西”在開始之前,請確保你的環境符合以下條件(依據源文件):
pnpm套件管理器- Node.js 開發環境
- 專案原始碼路徑:
src/gateway/protocol/schema.ts與src/gateway/server.ts
Gateway 的通訊邏輯非常直覺,所有的 WebSocket 訊息都屬於以下三種框架之一:
- Request:
{ type: "req", id, method, params } - Response:
{ type: "res", id, ok, payload | error } - Event:
{ type: "event", event, payload, seq?, stateVersion? }
1. 連線流程
Section titled “1. 連線流程”連線後發送的第一個訊息必須是 connect 請求。之後你才能呼叫其他方法(如 health, send)或訂閱事件。
用戶端 Gateway |---- req:connect -------->| |<---- res:hello-ok --------| |<---- event:tick ----------| |---- req:health ---------->| |<---- res:health ----------|2. 最小實作範例 (Node.js)
Section titled “2. 最小實作範例 (Node.js)”這是一個最簡單的用戶端實作,示範如何完成連線並檢查健康狀態:
import { WebSocket } from "ws";
const ws = new WebSocket("ws://127.0.0.1:18789");
ws.on("open", () => { ws.send( JSON.stringify({ type: "req", id: "c1", method: "connect", params: { minProtocol: 3, maxProtocol: 3, client: { id: "cli", displayName: "example", version: "dev", platform: "node", mode: "cli", }, }, }), );});
ws.on("message", (data) => { const msg = JSON.parse(String(data)); if (msg.type === "res" && msg.id === "c1" && msg.ok) { ws.send(JSON.stringify({ type: "req", id: "h1", method: "health" })); } if (msg.type === "res" && msg.id === "h1") { console.log("health:", msg.payload); ws.close(); }});實戰演練:新增一個 API 方法
Section titled “實戰演練:新增一個 API 方法”假設你要新增一個 system.echo 方法,傳入文字並回傳 { ok: true, text }。
第一步:定義 Schema
Section titled “第一步:定義 Schema”在 src/gateway/protocol/schema.ts 中加入定義,並導出型別:
export const SystemEchoParamsSchema = Type.Object( { text: NonEmptyString }, { additionalProperties: false },);
export const SystemEchoResultSchema = Type.Object( { ok: Type.Boolean(), text: NonEmptyString }, { additionalProperties: false },);
// 註冊到 ProtocolSchemas 並導出 Static 型別export type SystemEchoParams = Static<typeof SystemEchoParamsSchema>;export type SystemEchoResult = Static<typeof SystemEchoResultSchema>;第二步:建立驗證器
Section titled “第二步:建立驗證器”在 src/gateway/protocol/index.ts 中,匯出 AJV 驗證函式:
export const validateSystemEchoParams = ajv.compile<SystemEchoParams>(SystemEchoParamsSchema);第三步:實作伺服器邏輯
Section titled “第三步:實作伺服器邏輯”在 src/gateway/server-methods/system.ts 加入處理器:
export const systemHandlers: GatewayRequestHandlers = { "system.echo": ({ params, respond }) => { const text = String(params.text ?? ""); respond(true, { ok: true, text }); },};別忘了在 src/gateway/server.ts 的 METHODS 列表中加入 "system.echo"。
第四步:同步生成檔案
Section titled “第四步:同步生成檔案”執行以下指令來更新 JSON Schema 與 Swift 模型:
pnpm protocol:check如果你在開發過程中遇到問題,請檢查以下源文檔提到的常見狀況:
- 連線被拒絕:檢查
connect請求是否為第一個發出的訊息。伺服器會驗證minProtocol與maxProtocol,如果版本不匹配會直接拒絕。 - 欄位驗證失敗:大部分物件都開啟了
additionalProperties: false,請確保發送的 JSON 沒有包含多餘的欄位。 - Swift 端的未知訊息:Swift 生成器會保留未知框架類型(保留原始 payload),這是為了確保舊版用戶端不會因為收到新事件而直接當機。
- 副作用失效:對於有副作用的方法(如
send,chat.send),請確保在params中帶上idempotencyKey。
想要更自動化的開發體驗?試試 AI Setup Assistant。
- Gateway architecture - 深入了解架構設計
- 檢視產出的 JSON Schema
- 查看
src/gateway/server.ts了解完整的METHODS與EVENTS清單
OpenClaw Expert
還是卡住了?
如果這篇文件沒有解決你的情境,直接問 OpenClaw Expert,拿到可執行步驟。