xxrpc_client
xxrpc_client generates Protobuf messages and typed clients for every Protobuf RPC cardinality. Each endpoint associates one or more .proto sources with an HTTP URL. Generate exactly one language per call with out_es or out_go.
Only clients support Go output. xxrpc_handler generates ECMAScript backends.
Arguments
| Argument | Required | Description |
|---|---|---|
endpoints | Yes | Non-empty list of dictionaries containing srcs and url. |
out_es | One output | Project-relative ECMAScript output directory. |
deps | No | Dependencies activated before tool installation and generation. Defaults to []. |
out_go | One output | Project-relative Go output directory. |
Exactly one of out_es and out_go must be set. Each endpoint dictionary has exactly these fields:
| Field | Description |
|---|---|
srcs | Non-empty list of project-relative .proto files. A source can occur in only one endpoint URL. |
url | Absolute http or https URL embedded as the generated client's default endpoint. |
Protocol
Unary methods use regular HTTP requests:
| Part | Value |
|---|---|
| HTTP method | POST |
Content-Type | application/protobuf |
X-XXRPC-Service | Fully qualified Protobuf service name, such as example.greeter.v1.Greeter |
X-XXRPC-Method | Method name as declared in the .proto file, such as Greet |
X-XXRPC-Streaming | 0; a mismatch returns HTTP 400 |
| Body | Raw encoded input message |
Any streaming method uses one WebSocket per RPC call. The client changes the endpoint scheme from http to ws or from https to wss, preserves the configured path and query, and adds xxrpc-service and xxrpc-method query parameters.
The WebSocket requests subprotocol xxrpc.streaming.v1. Each binary WebSocket message contains one xxRPC control or Protobuf frame. Calls use a 4 MiB message limit, a 4 MiB byte-credit window, and a 1024-message credit window in each direction. STATUS is the canonical completion result; a socket closing without it is reported as unavailable.
ECMAScript
ECMAScript output requires protoc and protoc-gen-es in the task environment. Load protoc from an exact @protobuf package. Install @bufbuild/protoc-gen-es version 2 in the project and expose node_modules/.bin through deps.
Protobuf-ES writes a <source>_pb.js module and a <source>_pb.d.ts declaration. Each generated <source>_xxrpc.ts exports one <Service>Client class per Protobuf service. Its constructor accepts an optional endpoint override and optional XXRPCClientOptions with a custom WebSocket factory. It defaults to the configured endpoint and the browser's global WebSocket.
| Protobuf method | Client input | Client result |
|---|---|---|
| Unary | Input | Promise<Output> |
| Server streaming | Input | AsyncIterable<Output> |
| Client streaming | AsyncIterable<Input> | Promise<Output> |
| Bidirectional streaming | AsyncIterable<Input> | AsyncIterable<Output> |
All methods accept optional XXRPCCallOptions with an AbortSignal. Aborting cancels the call. Breaking out of a response AsyncIterable also cancels its WebSocket and closes the request iterator. XXRPCError.code contains the RPC status and unary failures additionally expose httpStatus.
load("@[email protected]", "npm_install")
load("@os@1", "env_prepend")
load("@[email protected]", "protoc")
load("@xxrpc@1", "xxrpc_client")
install = npm_install()
rpc_client = xxrpc_client(
endpoints=[
{
"srcs": ["contracts/greeter.proto"],
"url": "http://localhost:4321/greeter",
},
],
out_es="frontend/generated",
deps=[
protoc,
install,
env_prepend("PATH", "node_modules/.bin"),
],
)
Go
Go output requires protoc and go in the task environment. xxRPC automatically installs Google's official google.golang.org/protobuf/cmd/protoc-gen-go at the latest v1 release into an isolated tool directory. Do not install or pass protoc-gen-go yourself.
Every input and imported .proto file must provide the Go import path required by protoc-gen-go, normally with go_package. Well-known Protobuf types already provide it.
option go_package = "example.com/project/generated/contracts;contracts";
Generation uses source-relative paths. It writes the official <source>.pb.go, an xxRPC <source>_xxrpc.go for files containing services, and one xxrpc_runtime.go per generated Go package directory. Generated runtime code imports google.golang.org/protobuf/proto and github.com/coder/websocket; declare those modules in the consuming Go module.
Each service exposes New<Service>XXRPCClient(options...). The configured URL is used by default. XXRPCWithEndpoint, XXRPCWithHTTPClient, and XXRPCWithWebSocketDialer provide explicit overrides.
| Protobuf method | Generated Go API |
|---|---|
| Unary | Method(ctx, *Input) (*Output, error) |
| Server streaming | Method(ctx, *Input) (*ServiceMethodXXRPCClient, error) and Recv |
| Client streaming | Method(ctx) (*ServiceMethodXXRPCClient, error), Send, and CloseAndRecv |
| Bidirectional streaming | Method(ctx) (*ServiceMethodXXRPCClient, error), Send, Recv, and CloseSend |
Streaming constructors return after the WebSocket handshake and xxRPC ACCEPT. Recv returns io.EOF only after a successful terminal status. Close cancels a stream immediately, and CloseSend is idempotent. A stream safely supports one sender and one receiver at the same time.
Failures can be inspected with errors.As into *XXRPCError. It exposes Code, Message, HTTPStatus, and an underlying Cause. Context cancellation and deadlines remain available through errors.Is.
load("@[email protected]", "go")
load("@[email protected]", "protoc")
load("@xxrpc@1", "xxrpc_client")
rpc_client = xxrpc_client(
endpoints=[
{
"srcs": ["contracts/greeter.proto"],
"url": "http://localhost:4321/greeter",
},
],
out_go="generated",
deps=[protoc, go],
)
client, err := contracts.NewGreeterXXRPCClient()
if err != nil {
return err
}
response, err := client.Greet(ctx, &contracts.GreetRequest{Name: "Go"})
if err != nil {
return err
}
Output Ownership
The selected output directory is owned by the xxRPC task. Obsolete Protobuf and xxRPC generated files from preceding generations are removed before generation; unmanaged files are retained.
See a complete example in examples/rpc.