GRPC Annotations in Tonic (Rust)
·
One pretty neat feature to have when operating a GRPC API is documentation. It can be almost cost-free by using annotations. With Tonic, it is possible to have the endpoints auto documented into a Swagger or OpenAPI documentation.
A Tonic GRPC server working with annotations
Lets try for this api specification,
grpc/echo.proto
:
syntax = "proto3";
package api;
option go_package = "api";
import "google/api/annotations.proto";
message Message {
string value = 1;
}
service EchoService {
rpc Echo(Message) returns (Message) {
option (google.api.http) = {
post: "/v1/example/echo"
body: "*"
};
}
}
and this rust implementation,
src/main.rs
:
use tonic::{transport::Server, Request, Response, Status};
use crate::api::echo_service_server::{EchoService, EchoServiceServer};
use api::Message;
pub mod api {
tonic::include_proto!("api");
}
#[derive(Debug, Default)]
pub struct EchoAPI {}
#[tonic::async_trait]
impl EchoService for EchoAPI {
async fn echo(
&self,
request: Request<Message>,
) -> Result<Response<Message>, Status> {
let message = request.into_inner();
println!("received {:?}", message.value);
Ok(Response::new(Message { value: "response".into() }))
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addr = "0.0.0.0:7000".parse()?;
println!("listening on port {:?}", addr);
Server::builder()
.add_service(EchoServiceServer::new(EchoAPI::default()))
.serve(addr)
.await?;
Ok(())
}
and build.rs
:
use failure::{Error};
fn main() -> Result<(), Error> {
tonic_build::configure()
.compile(
&["grpc/echo.proto"],
&["googleapis", "grpc"],
)?;
Ok(())
}
and in Cargo.toml
:
[dependencies]
failure = "^0.1" // ༼◕_◕༽ anyhow would be better
prost = "0.6"
tonic = { version = "^0.3", features = ["tls"] }
tokio = { version = "^0.2", features = ["macros"] }
[build-dependencies]
failure = "^0.1"
tonic-build = "^0.3"
then add .gitmodules
:
[submodule "googleapis"]
path = googleapis
url = git@github.com:googleapis/googleapis.git
don’t forget to git submodule update --remote
Generating a swagger documentation
You need golang, the protobuf compiler and swagger
To install protoc on linux:
#! /bin/bash
apt-get -qq update
apt-get install -y build-essential wget zip
wget https://github.com/protocolbuffers/protobuf/releases/download/v3.13.0/protoc-3.13.0-linux-x86_64.zip
unzip protoc-3.13.0-linux-x86_64.zip
rm -f *.zip
mv bin/* /usr/local/bin
mv include/* /usr/local/include/
protoc --version
To install/update gprc gateway extensions:
go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway &&\
go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger &&\
go get -u github.com/golang/protobuf/protoc-gen-go
To generate swagger documentation:
protoc -I/usr/local/include -I. \
-I$GOPATH/src \
-I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
--swagger_out=logtostderr=true:. \
echo.proto
docker run -p 80:8080 -e BASE_URL=/ -e SWAGGER_JSON=/swag/echo.swagger.json -v `pwd`:/swag swaggerapi/swagger-ui
With this documentation and observability offered by opentelemetry-rust, you can have production ready grpc api in Rust.
From here, just enjoy the ride.