Cap'n Web, um novo sistema de RPC para navegadores e servidores web
(blog.cloudflare.com)- Cap'n Web é um novo protocolo de RPC implementado em TypeScript, otimizado para o ambiente web e capaz de rodar em vários runtimes JavaScript
- Sem schemas nem boilerplate incômodo, oferece serialização baseada em JSON e um formato de dados legível por humanos
- Com um modelo baseado em object-capability, permite chamadas bidirecionais, passagem de referências de funções e objetos, promise pipelining e implementação de padrões de segurança
- Suporta diversos ambientes de rede, como WebSocket, HTTP e postMessage, e é open source leve, com menos de 10kB
- Além de resolver o problema de waterfall semelhante ao GraphQL, também permite modelar RPC de forma natural, como em APIs JavaScript comuns
O que é o Cap'n Web
- Cap'n Web é um sistema open source de RPC (protocolo) baseado em TypeScript desenvolvido pela Cloudflare
- Foi inspirado no Cap'n Proto, mas funciona sem definição de schema separada e adota uma forma de serialização amigável para humanos usando JSON
- É integrado ao TypeScript, melhorando a experiência do desenvolvedor com autocomplete e checagem de tipos; a validação de tipos em runtime pode ser tratada separadamente, como com type guards
- Suporta protocolos de rede como HTTP, WebSocket e postMessage e roda nos principais navegadores, Cloudflare Workers, Node.js e outros
- Tem estrutura leve, sem dependências, e fica com menos de 10kB após minify + gzip
O modelo object-capability (OCap) do Cap'n Web
- Adota um modelo baseado em object-capability, permitindo expressar mais coisas do que sistemas de RPC tradicionais
- Chamadas bidirecionais: cliente e servidor podem chamar funções um do outro
- Passagem de referências de funções e objetos: ao enviar uma função ou objeto via RPC, o outro lado recebe um stub e, ao chamar, a execução acontece no local de origem
- Promise Pipelining: ao encadear vários RPCs, tudo pode ser processado com uma única ida e volta de rede
- Padrões de segurança: é possível implementar naturalmente controles de segurança como autorização e gerenciamento de sessão
Uso básico
-
Exemplo de cliente
import { newWebSocketRpcSession } from "capnweb" let api = newWebSocketRpcSession("wss://example.com/api") let result = await api.hello("World") console.log(result) -
Exemplo de servidor (baseado em 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}) } } -
É simples adicionar métodos à API, passar funções de callback do cliente e definir/aplicar interfaces TypeScript
O que é RPC e quais são as características do Cap'n Web
- RPC (Remote Procedure Call) é um conceito que permite a dois programas em rede se comunicarem como se estivessem fazendo chamadas de função
- Diferente dos protocolos HTTP/REST tradicionais, RPC oferece uma abstração de chamada de função, permitindo escrever código alinhado à forma como os desenvolvedores pensam
- O Cap'n Web combina bem com o fluxo do JavaScript moderno, incluindo async/await, Promise e suporte a Exception
- Diferente das controvérsias históricas sobre RPC (chamadas síncronas, erros de rede), nos ambientes JS modernos ele pode ser usado de forma mais segura e eficiente
Cenários de uso do Cap'n Web
- É útil em qualquer ambiente que exija comunicação de rede entre duas aplicações JavaScript
- Cliente-servidor, chamadas entre microsserviços etc.
- É especialmente adequado para webapps de colaboração em tempo real e interações que atravessam fronteiras de segurança complexas
- Ainda está em fase experimental, sendo mais útil para desenvolvedores abertos à adoção de tecnologias recentes
Vários recursos
Modo de lote HTTP
-
Quando não é necessário manter uma conexão persistente, é possível usar o modo de lote (batch) HTTP para agrupar várias chamadas RPC de uma vez
import { newHttpBatchRpcSession } from "capnweb" let batch = newHttpBatchRpcSession("https://example.com/api") let result = await batch.hello("World") console.log(result) -
Dentro de um mesmo lote, várias chamadas podem ser executadas ao mesmo tempo, com os resultados recebidos em paralelo
let promise1 = batch.hello("Alice") let promise2 = batch.hello("Bob") let [result1, result2] = await Promise.all([promise1, promise2])
Promise Pipelining (chamadas encadeadas)
-
Suporta o uso do resultado da chamada anterior diretamente como argumento da próxima, sem esperar o resultado anterior
-
Exemplo) a Promise retornada por
getMyName()pode ser passada direto parahello(), resolvendo tudo em uma única ida e volta de redelet namePromise = batch.getMyName() let result = await batch.hello(namePromise) -
As Promises do Cap'n Web funcionam como objetos proxy, permitindo encadeamento adicional de métodos sem atraso
let sessionPromise = batch.authenticate(apiKey) let name = await sessionPromise.whoami()
Segurança: autenticação e object-capability
- Pelo método
authenticate, em caso de sucesso é atribuído um objeto de permissão (sessão), e depois disso as funções podem ser chamadas sem etapas extras de autenticação - Diferente de RPCs tradicionais, não é possível falsificar o objeto de sessão, e métodos que exigem permissão não podem ser acessados sem autenticação
- Isso supera naturalmente limitações estruturais do WebSocket e garante consistência na lógica de autenticação
- Ao declarar interfaces da API em TypeScript, elas podem ser aplicadas automaticamente entre cliente e servidor, garantindo autocomplete e segurança de tipos
Comparação com GraphQL e diferenciais do Cap'n Web
-
O GraphQL alivia o problema de waterfall do REST, mas exige a adoção de uma nova linguagem, schema e toolchain
-
O Cap'n Web resolve o problema de waterfall apenas com código JavaScript e,
- com suporte a promise pipelining e referências de objetos, permite modelar de forma natural chamadas aninhadas ou lógica de transações complexas
let user = api.createUser({ name: "Alice" }) let friendRequest = await user.sendFriendRequest("Bob") -
Pode ser usado de forma parecida com APIs JavaScript, sem a complexidade nem o custo de aprendizado e manutenção do GraphQL
Operações com arrays (array.map etc.) e otimização
-
No Cap'n Web, é possível fazer operações
mapem cada elemento de um array sem rodadas extras de rede -
A função de callback do
mapé executada uma vez no cliente para registrar a operação (record-replay), enviada ao servidor e então processada em lote no lado do servidorlet friendsWithPhotos = friendsPromise.map(friend => { return {friend, photo: api.getUserPhoto(friend.id)} }) let results = await friendsWithPhotos -
Por meio de uma linguagem específica de domínio (DSL) limitada, a expressão parece uma função JavaScript, mas na prática usa o protocolo do Cap'n Web para otimizar várias chamadas
Estrutura interna do protocolo e fluxo de comunicação
- Transmite dados estruturados com JSON + pré-processamento especial, com suporte a tipos especiais como arrays e datas
- Como é um protocolo simétrico, permite comunicação bidirecional sem distinção entre cliente e servidor
- Cada parte (por exemplo, Alice e Bob) gerencia tabelas de export/import e distingue referências de objetos e funções por ID
- Por meio de mensagens push/pull e atribuição de IDs de Promise, é possível refletir várias chamadas em uma única rodada de comunicação
Status atual e casos de uso
- O Cap'n Web ainda é um open source experimental, mas já está sendo usado em serviços reais, como remote bindings do Cloudflare Wrangler
- Estão previstos mais posts de blog e vários experimentos de frontend
- É publicado sob licença MIT e qualquer pessoa pode adotá-lo livremente
- Ir para o repositório no GitHub
Ainda não há comentários.