ブラウザとWebサーバーのための新しいRPCシステム Cap'n Web
(blog.cloudflare.com)- Cap'n WebはTypeScriptで実装された新しいRPCプロトコルで、Web環境に最適化され、さまざまなJavaScriptランタイムで動作する
- スキーマや煩雑なボイラープレートなしで、JSONベースのシリアライズと人間が読めるデータ形式を提供する
- オブジェクトケーパビリティベースのモデルにより、双方向呼び出し、関数・オブジェクト参照の受け渡し、Promiseパイプライニング、セキュリティパターンの実装が可能
- WebSocket, HTTP, postMessage など多様なネットワーク環境をサポートし、10kB以下の軽量オープンソース
- GraphQLに似たwaterfall問題の解決だけでなく、一般的なJavaScript APIのような自然なRPCモデリングを可能にする
Cap'n Webとは何か
- Cap'n WebはCloudflareが開発したTypeScriptベースのオープンソースRPC(protocol)システム
- Cap'n Protoに着想を得ているが、別途スキーマ定義なしで動作し、JSONを活用した人間にやさしいシリアライズ方式を採用
- TypeScriptと統合されており、自動補完や型チェックなど開発者体験を向上させ、ランタイムの型検証は別途(type guardなど)で処理できる
- HTTP, WebSocket, postMessageなどのネットワークプロトコルをサポートし、主要ブラウザ・Cloudflare Workers・Node.jsなどで動作
- 依存関係のない軽量な構造で、minify + gzip時に10kB未満で提供される
Cap'n Webのオブジェクトケーパビリティベースモデル(OCap)
- オブジェクトケーパビリティ(object-capability)ベースのモデルを採用し、既存のRPCシステムより多様な表現が可能
- 双方向呼び出し: クライアントとサーバーが互いに関数を呼び出せる
- 関数・オブジェクト参照の受け渡し: 関数やオブジェクトをRPCで渡すと、相手はスタブを受け取り、呼び出し時に元の場所で実行される
- Promise Pipelining: 複数のRPCをチェーンでつなぐ際、1回のネットワーク往復で処理
- セキュリティパターン: 権限付与やセッション管理などのセキュリティ制御を自然に実装できる
基本的な使い方
-
クライアントの例
import { newWebSocketRpcSession } from "capnweb" let api = newWebSocketRpcSession("wss://example.com/api") let result = await api.hello("World") console.log(result) -
サーバーの例(Cloudflare Workerベース)
import { RpcTarget, newWorkersRpcResponse } from "capnweb" class MyApiServer extends RpcTarget { hello(name) { return `Hello, ${name}!` } } export default { fetch(request, env, ctx) { let url = new URL(request.url) if (url.pathname === "/api") { return newWorkersRpcResponse(request, new MyApiServer()) } return new Response("Not found", {status: 404}) } } -
APIへのメソッド追加、クライアントのコールバック関数の受け渡し、TypeScriptインターフェースの定義と適用を簡単に行える
RPCとは何か、そしてCap'n Webの特徴
- **RPC(Remote Procedure Call)**は、ネットワーク上の2つのプログラムがあたかも関数呼び出しのように通信できるようにする概念
- 従来のHTTP/RESTプロトコルと異なり、RPCでは関数呼び出しの抽象化によって開発者の思考様式に一致するコードを書ける
- Cap'n Webはasync/await, Promise, Exceptionサポートなど、最新のJavaScriptの流れとよく合う
- RPCをめぐる歴史的な論争(同期呼び出し、ネットワーク障害)とは異なり、現代のJS環境ではより安全かつ効率的に利用できる
Cap'n Webの活用シナリオ
- 2つのJavaScriptアプリケーション間でネットワーク通信が必要なあらゆる環境で活躍
- クライアント-サーバー、マイクロサービス間呼び出しなど
- 特にリアルタイム共同作業Webアプリや、複雑なセキュリティ境界をまたぐ相互作用に適している
- 実験的な段階にあり、新しい技術の導入に前向きな開発者にとって特に有益
さまざまな機能
HTTPバッチモード
-
継続的な接続が不要な場合、HTTPバッチ(batch)モードで複数のRPC呼び出しを一度にまとめて処理できる
import { newHttpBatchRpcSession } from "capnweb" let batch = newHttpBatchRpcSession("https://example.com/api") let result = await batch.hello("World") console.log(result) -
1つのバッチ内で複数の呼び出しを同時実行し、結果を並列に受け取れる
let promise1 = batch.hello("Alice") let promise2 = batch.hello("Bob") let [result1, result2] = await Promise.all([promise1, promise2])
Promise Pipelining(チェーン呼び出し)
-
前の呼び出し結果を待たずに、その結果をすぐ次の呼び出しの引数として使う方式をサポート
-
例)
getMyName()の結果Promiseをそのままhello()に渡し、1回のネットワーク往復で処理let namePromise = batch.getMyName() let result = await batch.hello(namePromise) -
Cap'n WebのPromiseはプロキシ(proxy)オブジェクトとして動作し、追加メソッド呼び出し時も遅延なくチェーン処理できる
let sessionPromise = batch.authenticate(apiKey) let name = await sessionPromise.whoami()
セキュリティ: 認証とオブジェクトケーパビリティ
- authenticateメソッドにより成功時に権限(セッション)オブジェクトを割り当て、その後は追加認証なしで機能を呼び出せる
- 従来のRPCと異なりセッションオブジェクトを偽造できず、認証なしでは権限が必要なメソッドにアクセスできない
- WebSocketの構造的な制約を自然に克服し、認証ロジックの一貫性を保証
- TypeScriptでAPIインターフェースを宣言すれば、クライアント〜サーバーに自動適用でき、自動補完と型安全性を確保できる
GraphQLとの比較とCap'n Webの差別化ポイント
-
GraphQLはRESTのwaterfall(多段階呼び出し)問題を緩和するが、新しい言語・スキーマ・ツールチェーンの導入が必要
-
Cap'n WebはJavaScriptコードだけでwaterfall問題を解決し、
- Promiseパイプライニング / オブジェクト参照のサポートにより、ネストした呼び出しや複合トランザクションロジックを自然にモデル化できる
let user = api.createUser({ name: "Alice" }) let friendRequest = await user.sendFriendRequest("Bob") -
GraphQLの複雑さや学習・運用コストなしに、JavaScript APIのように活用できる
配列演算(array.mapなど)と最適化
-
Cap'n Webでは配列の各要素に対して追加のネットワーク往復なしでmap演算が可能
-
mapコールバック関数をクライアントで一度実行して演算内容を記録(record-replay)し、サーバーへ送信してサーバー側で一括処理する
let friendsWithPhotos = friendsPromise.map(friend => { return {friend, photo: api.getUserPhoto(friend.id)} }) let results = await friendsWithPhotos -
制限付きのドメイン特化言語(DSL)により、JavaScript関数のように表現しつつ、実際にはCap'n Webプロトコルを活用して複数呼び出しを最適化処理する
内部プロトコル構造と通信フロー
- JSON + 特別な前処理による構造化データ転送で、配列・日付などの特別な型もサポート
- 対称的なプロトコルによりクライアント・サーバーの区別なく双方向通信が可能
- 各パーティ(例: AliceとBob)はexport/importテーブルを管理し、オブジェクト・関数参照をIDで区別
- push/pullメッセージやPromise IDの割り当てなどにより、1回のラウンドトリップで多数の呼び出しを反映できる
現状と適用事例
- Cap'n Webはまだ実験的なオープンソースで、Cloudflare Wranglerのremote bindingsなど実サービスで活用されている
- 追加のブログ投稿やさまざまなフロントエンド実験も予定されている
- MITライセンスで公開され、誰でも自由に適用可能
- GitHubリポジトリはこちら
まだコメントはありません。