gRPC for Rust: Libraries and Examples
gRPC is a high-performance remote procedure call (RPC) framework developed by Google. It uses Protocol Buffers (protobuf) for data serialization and HTTP/2 for transport. Thanks to strict typing, bidirectional streaming, and low latency, gRPC has become a standard for microservice architecture. In the Rust ecosystem, there are two main libraries for working with gRPC: Tonic and grpc-rs. In this article, we will examine their features and provide practical examples.
1. Tonic — Modern and Asynchronous
Tonic is the most popular gRPC library for Rust. It is built on top of tokio and hyper, is fully asynchronous, and integrates well with the Rust ecosystem. Tonic supports all four types of gRPC calls: unary, server streaming, client streaming, and bidirectional streaming.
Installation and Setup
Add dependencies to Cargo.toml:
[dependencies]tonic = "0.12"prost = "0.13"tokio = { version = "1", features = ["full"] }
[build-dependencies]tonic-build = "0.12"Defining a Protobuf Service
Create a file proto/hello.proto:
syntax = "proto3";
package hello;
service Greeter { rpc SayHello (HelloRequest) returns (HelloReply);}
message HelloRequest { string name = 1;}
message HelloReply { string message = 1;}Building Protobuf
In build.rs, specify:
fn main() -> Result<(), Box<dyn std::error::Error>> { tonic_build::compile_protos("proto/hello.proto")?; Ok(())}Server Implementation
Example of a simple gRPC server using Tonic:
use tonic::{transport::Server, Request, Response, Status};use hello::greeter_server::{Greeter, GreeterServer};use hello::{HelloRequest, HelloReply};
pub mod hello { tonic::include_proto!("hello");}
#[derive(Default)]pub struct MyGreeter;
#[tonic::async_trait]impl Greeter for MyGreeter { async fn say_hello( &self, request: Request<HelloRequest>, ) -> Result<Response<HelloReply>, Status> { let name = request.into_inner().name; let reply = HelloReply { message: format!("Hello, {}!", name), }; Ok(Response::new(reply)) }}
#[tokio::main]async fn main() -> Result<(), Box<dyn std::error::Error>> { let addr = "[::1]:50051".parse()?; let greeter = MyGreeter::default();
Server::builder() .add_service(GreeterServer::new(greeter)) .serve(addr) .await?;
Ok(())}Client
use hello::greeter_client::GreeterClient;use hello::HelloRequest;
pub mod hello { tonic::include_proto!("hello");}
#[tokio::main]async fn main() -> Result<(), Box<dyn std::error::Error>> { let mut client = GreeterClient::connect("http://[::1]:50051").await?;
let request = tonic::Request::new(HelloRequest { name: "World".into(), });
let response = client.say_hello(request).await?; println!("Server response: {}", response.into_inner().message); Ok(())}2. grpc-rs — A Mature Alternative
grpc-rs is a library from the TiKV team, built on top of the C library gRPC Core. It provides maximum compatibility with the official gRPC C framework but requires installing system dependencies (cmake, protobuf). grpc-rs supports synchronous and asynchronous calls but is less convenient to use than Tonic.
Example Server with grpc-rs
use grp