Cap'n Web: a new RPC system for browsers and web servers with AMAZING features
-
Full Read well worth it: https://blog.cloudflare.com/capnweb-javascript-rpc-library/
This would be a huge boost for Cloudron 9.x!
12 min read
Allow us to introduce Cap'n Web, an RPC protocol and implementation in pure TypeScript.
Cap'n Web is a spiritual sibling to Cap'n Proto, an RPC protocol I (Kenton) created a decade ago, but designed to play nice in the web stack. That means:
-
Like Cap'n Proto, it is an object-capability protocol. ("Cap'n" is short for "capabilities and".) We'll get into this more below, but it's incredibly powerful.
-
Unlike Cap'n Proto, Cap'n Web has no schemas. In fact, it has almost no boilerplate whatsoever. This means it works more like the JavaScript-native RPC system in Cloudflare Workers.
-
That said, it integrates nicely with TypeScript.
-
Also unlike Cap'n Proto, Cap'n Web's underlying serialization is human-readable. In fact, it's just JSON, with a little pre-/post-processing.
-
It works over HTTP, WebSocket, and postMessage() out-of-the-box, with the ability to extend it to other transports easily.
-
It works in all major browsers, Cloudflare Workers, Node.js, and other modern JavaScript runtimes.
-
The whole thing compresses (minify+gzip) to under 10 kB with no dependencies.
-
It's open source under the MIT license.
Cap'n Web is more expressive than almost every other RPC system, because it implements an object-capability RPC model. That means it:
-
Supports bidirectional calling. The client can call the server, and the server can also call the client.
-
Supports passing functions by reference: If you pass a function over RPC, the recipient receives a "stub". When they call the stub, they actually make an RPC back to you, invoking the function where it was created. This is how bidirectional calling happens: the client passes a callback to the server, and then the server can call it later.
-
Similarly, supports passing objects by reference: If a class extends the special marker type
RpcTarget
, then instances of that class are passed by reference, with method calls calling back to the location where the object was created. -
Supports promise pipelining. When you start an RPC, you get back a promise. Instead of awaiting it, you can immediately use the promise in dependent RPCs, thus performing a chain of calls in a single network round trip.
-
Supports capability-based security patterns.
In short, Cap'n Web lets you design RPC interfaces the way you'd design regular JavaScript APIs – while still acknowledging and compensating for network latency.
The best part is, Cap'n Web is absolutely trivial to set up.
A client looks like this:
import { newWebSocketRpcSession } from "capnweb"; // One-line setup. let api = newWebSocketRpcSession("wss://example.com/api"); // Call a method on the server! let result = await api.hello("World"); console.log(result);
And here's a complete Cloudflare Worker implementing an RPC server:
import { RpcTarget, newWorkersRpcResponse } from "capnweb"; // This is the server implementation. class MyApiServer extends RpcTarget { hello(name) { return `Hello, ${name}!` } } // Standard Workers HTTP handler. export default { fetch(request, env, ctx) { // Parse URL for routing. let url = new URL(request.url); // Serve API at `/api`. if (url.pathname === "/api") { return newWorkersRpcResponse(request, new MyApiServer()); } // You could serve other endpoints here... return new Response("Not found", {status: 404}); } }
That's it. That's the app.
-
You can add more methods to
MyApiServer
, and call them from the client. -
You can have the client pass a callback function to the server, and then the server can just call it.
-
You can define a TypeScript interface for your API, and easily apply it to the client and server.
It just works.
Much more at the link above.
-