Cap'n Web: Ein neues RPC-System für Browser und Webserver
(blog.cloudflare.com)- Cap'n Web ist ein neues, in TypeScript implementiertes RPC-Protokoll, das für Web-Umgebungen optimiert ist und in verschiedenen JavaScript-Runtimes läuft
- Es bietet JSON-basierte Serialisierung und ein menschenlesbares Datenformat – ganz ohne Schema oder umständlichen Boilerplate-Code
- Durch ein Object-Capability-basiertes Modell sind bidirektionale Aufrufe, die Übergabe von Funktions- und Objektreferenzen, Promise-Pipelining und die Umsetzung von Sicherheitsmustern möglich
- Es unterstützt verschiedene Netzwerkumgebungen wie WebSocket, HTTP, postMessage und ist ein leichtgewichtiges Open-Source-Projekt mit weniger als 10 kB
- Es löst nicht nur das Waterfall-Problem ähnlich wie GraphQL, sondern ermöglicht auch eine natürliche Modellierung von RPCs wie bei normalen JavaScript-APIs
Was ist Cap'n Web?
- Cap'n Web ist ein von Cloudflare entwickeltes Open-Source-RPC-System auf TypeScript-Basis
- Es ist von Cap'n Proto inspiriert, arbeitet aber ohne separate Schemadefinition und nutzt eine menschenfreundliche Serialisierung auf JSON-Basis
- Es ist in TypeScript integriert und verbessert damit die Developer Experience durch Autovervollständigung, Type-Checking usw.; Laufzeit-Typvalidierung kann separat behandelt werden, etwa mit Type Guards
- Es unterstützt Netzwerkprotokolle wie HTTP, WebSocket und postMessage und läuft in gängigen Browsern, Cloudflare Workers, Node.js und mehr
- Dank der leichtgewichtigen, abhängigkeitslosen Struktur bleibt es bei minify + gzip unter 10 kB
Das Object-Capability-Modell (OCap) von Cap'n Web
- Es verwendet ein Object-Capability-Modell, das mehr Ausdrucksmöglichkeiten bietet als herkömmliche RPC-Systeme
- Bidirektionale Aufrufe: Client und Server können gegenseitig Funktionen aufrufen
- Übergabe von Funktions- und Objektreferenzen: Wenn Funktionen oder Objekte per RPC übergeben werden, erhält die Gegenseite einen Stub, dessen Aufruf am Ursprungsort ausgeführt wird
- Promise Pipelining: Beim Verketten mehrerer RPCs ist nur ein einziger Netzwerk-Roundtrip nötig
- Sicherheitsmuster: Sicherheitskontrollen wie Autorisierung und Session-Management lassen sich auf natürliche Weise umsetzen
Grundlegende Nutzung
-
Client-Beispiel
import { newWebSocketRpcSession } from "capnweb" let api = newWebSocketRpcSession("wss://example.com/api") let result = await api.hello("World") console.log(result) -
Server-Beispiel (auf Basis eines Cloudflare Workers)
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}) } } -
Zusätzliche Methoden für die API, die Übergabe von Callback-Funktionen vom Client sowie die Definition und Anwendung von TypeScript-Interfaces lassen sich einfach umsetzen
Was ist RPC und was zeichnet Cap'n Web aus?
- RPC (Remote Procedure Call) ist ein Konzept, mit dem zwei Programme über ein Netzwerk so kommunizieren können, als würden sie Funktionen aufrufen
- Anders als bei traditionellen HTTP/REST-Protokollen ermöglicht RPC durch die Abstraktion von Funktionsaufrufen Code, der der Denkweise von Entwickler:innen entspricht
- Cap'n Web passt gut zum modernen JavaScript-Stil mit async/await, Promise und Exception-Support
- Anders als bei den historischen Kontroversen um RPC (synchrone Aufrufe, Netzwerkfehler) ist eine Nutzung in modernen JS-Umgebungen heute sicherer und effizienter möglich
Einsatzszenarien für Cap'n Web
- Geeignet für alle Umgebungen, in denen Netzwerkkommunikation zwischen zwei JavaScript-Anwendungen nötig ist
- Client-Server-Kommunikation, Aufrufe zwischen Microservices usw.
- Besonders geeignet für Web-Apps mit Echtzeit-Zusammenarbeit und für Interaktionen über komplexe Sicherheitsgrenzen hinweg
- Noch in einer experimentellen Phase und daher besonders interessant für Entwickler:innen, die offen für moderne Technologien sind
Verschiedene Funktionen
HTTP-Batch-Modus
-
Wenn keine dauerhafte Verbindung nötig ist, können im HTTP-Batch-Modus mehrere RPC-Aufrufe gebündelt und auf einmal verarbeitet werden
import { newHttpBatchRpcSession } from "capnweb" let batch = newHttpBatchRpcSession("https://example.com/api") let result = await batch.hello("World") console.log(result) -
Innerhalb eines einzelnen Batches können mehrere Aufrufe gleichzeitig ausgeführt und die Ergebnisse parallel empfangen werden
let promise1 = batch.hello("Alice") let promise2 = batch.hello("Bob") let [result1, result2] = await Promise.all([promise1, promise2])
Promise Pipelining (verkettete Aufrufe)
-
Unterstützt ein Modell, bei dem das Ergebnis eines vorherigen Aufrufs direkt als Argument für den nächsten Aufruf verwendet wird, ohne auf die vorherige Antwort zu warten
-
Beispiel: Das Ergebnis-Promise von
getMyName()wird direkt anhello()übergeben und mit nur einem Netzwerk-Roundtrip verarbeitetlet namePromise = batch.getMyName() let result = await batch.hello(namePromise) -
Die Promises von Cap'n Web verhalten sich wie Proxy-Objekte, sodass zusätzliche Methodenaufrufe ohne Verzögerung verkettet werden können
let sessionPromise = batch.authenticate(apiKey) let name = await sessionPromise.whoami()
Sicherheit: Authentifizierung und Object Capability
- Über die Methode
authenticatewird bei Erfolg ein Berechtigungsobjekt (Session) vergeben; danach können Funktionen ohne zusätzliche Authentifizierungsschritte aufgerufen werden - Anders als bei klassischen RPCs kann ein Session-Objekt nicht gefälscht werden, und auf Methoden mit Berechtigungsanforderungen kann ohne Authentifizierung nicht zugegriffen werden
- Strukturelle Einschränkungen von WebSocket werden auf natürliche Weise überwunden, während die Konsistenz der Authentifizierungslogik gewahrt bleibt
- Wenn API-Interfaces in TypeScript deklariert werden, lassen sie sich automatisch auf Client und Server anwenden und sorgen für Autovervollständigung sowie Typsicherheit
Vergleich mit GraphQL und das Alleinstellungsmerkmal von Cap'n Web
-
GraphQL entschärft das Waterfall-Problem von REST, erfordert aber die Einführung einer neuen Sprache, eines neuen Schemas und einer neuen Toolchain
-
Cap'n Web löst das Waterfall-Problem allein mit JavaScript-Code und
- unterstützt Promise Pipelining und Objektreferenzen, wodurch sich verschachtelte Aufrufe oder komplexe Transaktionslogik auf natürliche Weise modellieren lassen
let user = api.createUser({ name: "Alice" }) let friendRequest = await user.sendFriendRequest("Bob") -
Ohne die Komplexität sowie Lern- und Verwaltungskosten von GraphQL lässt es sich ähnlich wie eine JavaScript-API nutzen
Array-Operationen (array.map usw.) und Optimierung
-
Mit Cap'n Web sind
map-Operationen auf jedem Element eines Arrays ohne zusätzliche Netzwerk-Roundtrips möglich -
Die Callback-Funktion von
mapwird einmal auf dem Client ausgeführt, wobei der Recheninhalt aufgezeichnet wird (Record-Replay), dann an den Server gesendet und dort gesammelt verarbeitetlet friendsWithPhotos = friendsPromise.map(friend => { return {friend, photo: api.getUserPhoto(friend.id)} }) let results = await friendsWithPhotos -
Über eine begrenzte domänenspezifische Sprache (DSL) lässt sich dies wie eine JavaScript-Funktion ausdrücken, während intern das Cap'n-Web-Protokoll zur Optimierung mehrerer Aufrufe verwendet wird
Interne Protokollstruktur und Kommunikationsablauf
- Strukturierte Datenübertragung über JSON plus spezielle Vorverarbeitung, mit Unterstützung für spezielle Typen wie Arrays und Datumswerte
- Als symmetrisches Protokoll ermöglicht es bidirektionale Kommunikation ohne feste Trennung zwischen Client und Server
- Jede Partei (zum Beispiel Alice und Bob) verwaltet Export-/Import-Tabellen und unterscheidet Objekt- und Funktionsreferenzen anhand von IDs
- Durch Push-/Pull-Nachrichten und die Vergabe von Promise-IDs können viele Aufrufe in einem einzigen Roundtrip verarbeitet werden
Status und Einsatzbeispiele
- Cap'n Web ist noch experimentelle Open Source, wird aber bereits in realen Diensten wie den Remote Bindings von Cloudflare Wrangler eingesetzt
- Weitere Blogposts und verschiedene Frontend-Experimente sind geplant
- Es wird unter der MIT-Lizenz veröffentlicht und ist frei für alle nutzbar
- Direkt zum GitHub-Repository
Noch keine Kommentare.