grpc-webnext 0.1.1

Full bidirectional gRPC for the browser — real HTTP/2 over WebSockets (h2ts), plus JSON, REST, and a single-stream Frame protocol — served in front of any gRPC service, in-process (wrap a tonic Router) or as a standalone proxy.
docs.rs failed to build grpc-webnext-0.1.1
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Visit the last successful build: grpc-webnext-0.1.0

grpc-webnext

Full bidirectional gRPC for the browser — real HTTP/2 tunneled over WebSockets via h2ts, plus REST and JSON — served in front of any gRPC service.

crates.io docs.rs license

The Rust server for grpc-webnext — it brings the complete gRPC experience (all four call types, deadlines, metadata, trailers, cancellation) to the browser, on the same port as native gRPC. Use it two ways:

  • In-process — wrap a tonic Routes and serve grpc-webnext and native application/grpc from one listener, zero extra hops.
  • Standalone proxy — the grpc-webnext-proxy binary fronts any gRPC upstream, in any language, no .proto required (schema fetched via server reflection for the JSON/REST paths).

The browser side is the TypeScript client @grpc-webnext/client.

How it works

Two worlds share one endpoint; content-type and the WebSocket subprotocol disambiguate:

  • Binary (default) → real gRPC over h2ts. The browser runs a real HTTP/2 stack tunneled over a WebSocket by h2ts; this crate runs unmodified tonic behind an h2ts gateway. No translation — trailers, multiplexing, and flow control are native.
  • JSON (and binary streaming: "ws") → the custom Frame protocol. Unary rides Fetch (trailer buffered into the body, since browsers can't read HTTP trailers); streaming is one WebSocket per stream. Plaintext JSON stays debuggable in the browser's Network tab.
  • REST → google.api.http transcoding. Annotate methods to expose real HTTP verbs and JSON bodies on REST URLs — the grpc-gateway / Envoy standard.

Native application/grpc clients pass through byte-for-byte on the same port.

Install

Library:

[dependencies]
grpc-webnext = "0.1"

Proxy binary:

cargo install grpc-webnext        # installs `grpc-webnext-proxy`

In-process — serve grpc-webnext + native gRPC on one port

use grpc_webnext::{bind_and_serve_in_process, ServerConfig};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let routes = tonic::service::Routes::new(GreeterServer::new(MyGreeter::default()));
    let (addr, handle) = bind_and_serve_in_process(routes, ServerConfig::default()).await?;
    println!("listening on {addr}");
    handle.await?;
    Ok(())
}

Browsers reach it with @grpc-webnext/client; native gRPC clients (grpc-go, tonic, grpcurl…) connect to the same address unchanged.

Proxy — front an existing gRPC server

UPSTREAM=http://localhost:50051 LISTEN=127.0.0.1:8080 grpc-webnext-proxy

The proxy is schema-agnostic. For the JSON/REST transcoding paths it fetches message descriptors from the upstream via server reflection (SCHEMA=reflection) or a precompiled descriptor set (DESCRIPTOR_SET=path). The binary passthrough (h2ts) path needs no schema at all.

Authorization

No bespoke hooks — authorization is a per-RPC concern, uniform across every transport: a tonic interceptor in-process, or your mesh's ext_authz in front of the proxy.

Ecosystem

License

Dual-licensed under either Apache-2.0 or MIT, at your option.