Announcing Tonic 0.5
July 9, 2021
We are pleased to announce version 0.5 of Tonic, a native gRPC implementation in Rust. 0.5 is a big release and has been in the works for some time.
Some key new features are:
gRPC-Web
gRPC-Web is a protocol that allows clients to connect to gRPC services over HTTP/1.1, instead of the usual HTTP/2. A common use-case for gRPC-Web is JavaScript clients running in the browser. Previously that would require using a proxy to translate the HTTP/2 requests to HTTP/1.1.
However new crate tonic-web
allows regular Tonic servers to accept gRPC-Web
requests without the need of an external proxy.
Enabling gRPC-Web support is as easy as:
use tonic::transport::Server;
// code generated by tonic-build
use hello_world::greeter_server::{GreeterServer, Greeter};
struct MyGreeter;
#[tonic::async_trait]
impl Greeter for MyGreeter {
// ...
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addr = "0.0.0.0:3000".parse().unwrap();
let greeter = GreeterServer::new(MyGreeter);
// enable grpc-web support for our `greeter` service
let service = tonic_web::enable(greeter);
Server::builder()
// by default, tonic servers only accept http2 requests
// so we have to enable receiving http1 as well
.accept_http1(true)
.add_service(service)
.serve(addr)
.await?;
Ok(())
}
For more details see the tonic-web crate.
Compression
Tonic can now transparently compress and decompress requests, responses, and streams.
Enabling compression on a client is done like so:
let client = GreeterClient::new(channel)
// compress requests
.send_gzip()
/// accept compressed responses
.accept_gzip();
And like so on the server:
let service = GreeterServer::new(greeter)
// accept compressed requests
.accept_gzip()
// compress responses, if supported by the client
.send_gzip();
Note this requires enabling the compression
feature on both Tonic and
tonic-build
. See the docs for more details.
Improved Tower integration
Tonic has always had support for extending clients and servers through Tower's
Service
trait but in 0.5 the new Server::layer
method makes it even
easier. For example, we can add tracing and authorization to a service by using
middleware from tower-http
:
use tonic::transport::Server;
use tower_http::{
auth::RequireAuthorizationLayer,
trace::TraceLayer,
};
// The stack of middleware our service will be wrapped in
let layer = tower::ServiceBuilder::new()
// High level tracing of requests and responses
.layer(TraceLayer::new_for_grpc())
// Authorize all requests using a token
.layer(RequireAuthorizationLayer::bearer("my-secret-token"))
// Convert our `ServiceBuilder` into a `tower::Layer`
.into_inner();
Server::builder()
// Apply our middleware stack to the server
.layer(layer)
.add_service(GreeterServer::new(MyGreeter)
.serve(addr)
.await?;
More flexible interceptors
Interceptors are lightweight middleware that can, among other things, be used to modify the metadata of incoming requests and optionally reject them with a status.
However, Tonic's support for interceptors has always been fairly limited. For
example, you couldn't combine multiple interceptors, and would instead have to
use Tower's Service
abstraction, which is more powerful but also requires
more code to set up.
In Tonic 0.5, we have a new interceptor API that is as easy to use as before, but now uses Tower internally. That means interceptors can be applied in the same way as any other Tower middleware. For example adding multiple interceptors to a client is now possible with:
use tonic::{
Request, Status,
service::interceptor_fn,
transport::Endpoint
};
fn intercept_one(req: Request<()>) -> Result<Request<()>, Status> {
// ...
}
fn intercept_two(req: Request<()>) -> Result<Request<()>, Status> {
// ...
}
let channel = Endpoint::from_static("http://[::1]:50051").connect_lazy()?;
let intercepted_channel = tower::ServiceBuilder::new()
.layer(interceptor_fn(intercept_one))
.layer(interceptor_fn(intercept_two))
.service(channel);
let client = GreeterClient::new(intercepted_channel);
0.5 includes many other smaller features and improvements. The changelog has all the details.
As always, if you have questions you can find us in #tonic
in the Tokio
Discord server.