#rpc #grpc #grpc-web

tonic-web

grpc-web protocol translation for tonic services

12 releases (7 breaking)

0.11.0 Feb 8, 2024
0.10.2 Sep 28, 2023
0.9.2 Apr 17, 2023
0.9.0 Mar 31, 2023
0.1.0 Jul 8, 2021

#826 in Network programming

Download history 18260/week @ 2023-11-07 21277/week @ 2023-11-14 16182/week @ 2023-11-21 21534/week @ 2023-11-28 15531/week @ 2023-12-05 16664/week @ 2023-12-12 18895/week @ 2023-12-19 5927/week @ 2023-12-26 12932/week @ 2024-01-02 12982/week @ 2024-01-09 13506/week @ 2024-01-16 16012/week @ 2024-01-23 13154/week @ 2024-01-30 14546/week @ 2024-02-06 14877/week @ 2024-02-13 8141/week @ 2024-02-20

52,514 downloads per month
Used in 18 crates (12 directly)

MIT license

1MB
10K SLoC

tonic-web

Enables tonic servers to handle requests from grpc-web clients directly, without the need of an external proxy.

Getting Started

[dependencies]
tonic-web = "<tonic-web-version>"

Enabling tonic services

The easiest way to get started, is to call the function with your tonic service and allow the tonic server to accept HTTP/1.1 requests:

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let addr = "[::1]:50051".parse().unwrap();
    let greeter = GreeterServer::new(MyGreeter::default());

   Server::builder()
       .accept_http1(true)
       .layer(GrpcWebLayer::new())
       .add_service(greeter)
       .serve(addr)
       .await?;

   Ok(())
}

Examples

See the examples folder for a server and client example.


lib.rs:

grpc-web protocol translation for tonic services.

tonic_web enables tonic servers to handle requests from grpc-web clients directly, without the need of an external proxy. It achieves this by wrapping individual tonic services with a tower service that performs the translation between protocols and handles cors requests.

Enabling tonic services

The easiest way to get started, is to call the enable function with your tonic service and allow the tonic server to accept HTTP/1.1 requests:

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let addr = "[::1]:50051".parse().unwrap();
    let greeter = GreeterServer::new(MyGreeter::default());

    Server::builder()
       .accept_http1(true)
       .add_service(tonic_web::enable(greeter))
       .serve(addr)
       .await?;

   Ok(())
}

This will apply a default configuration that works well with grpc-web clients out of the box.

You can customize the CORS configuration composing the GrpcWebLayer with the cors layer of your choice.

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let addr = "[::1]:50051".parse().unwrap();
    let greeter = GreeterServer::new(MyGreeter::default());

    Server::builder()
       .accept_http1(true)
       // This will apply the gRPC-Web translation layer
       .layer(GrpcWebLayer::new())
       .add_service(greeter)
       .serve(addr)
       .await?;

   Ok(())
}

Alternatively, if you have a tls enabled server, you could skip setting accept_http1 to true. This works because the browser will handle ALPN.

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let cert = tokio::fs::read("server.pem").await?;
    let key = tokio::fs::read("server.key").await?;
    let identity = Identity::from_pem(cert, key);

    let addr = "[::1]:50051".parse().unwrap();
    let greeter = GreeterServer::new(MyGreeter::default());

    // No need to enable HTTP/1
    Server::builder()
       .tls_config(ServerTlsConfig::new().identity(identity))?
       .add_service(tonic_web::enable(greeter))
       .serve(addr)
       .await?;

   Ok(())
}

Limitations

  • tonic_web is designed to work with grpc-web-compliant clients only. It is not expected to handle arbitrary HTTP/x.x requests or bespoke protocols.
  • Similarly, the cors support implemented by this crate will only handle grpc-web and grpc-web preflight requests.
  • Currently, grpc-web clients can only perform unary and server-streaming calls. These are the only requests this crate is designed to handle. Support for client and bi-directional streaming will be officially supported when clients do.
  • There is no support for web socket transports.

Dependencies

~5.5–7.5MB
~132K SLoC