Structure of Tonic's proto include

When developing gRPC using Tonic _, it is necessary to properly incorporate protobuf in addition to building the server process.
Tonic uses PROST! , which is slightly different from the flow generated by the protoc command.

Alain , a code generation CLI tool equivalent to the logic of this article, is distributed as open source.

proto include

Consider the following example of embedding protobuf code.

syntax = "proto3";

package example.duck;

service ExampleDuck {
  rpc LameDuck(Dummy) returns (Dummy) {}
}

message Dummy {}

First, include proto using a macro.

pub mod example {
  pub mod duck {
        tonic::include_proto!("example.duck");
  }
}

At this time, it is important to define the mod hierarchy aligned with the protobuf package namespace.
If you make a mistake in the structure, you will face very confusing errors such as over-nested code output .

proto definition reference

The included proto definition is assigned to the namespace of the rust project along with the mod structure. In the previous example, it will be imported with a name like crate :: example :: duck::Dummy. Note that rpc is a snake case like crate::example::duck :: lame_duck().

In addition, structures such as servers are automatically generated according to the tool naming convention. There is an auto-generated file in the target / directory, and in individual cases you will have to check the code.

  • example::duck::LameDuckServer
  • example::duck::LameDuckClient
  • example::duck::LameDuckService

For the server implementation, if you do not implement all the rpc defined in proto, a compile-time error will occur.

Request and Response structure

Request is a tonic::Request<example::duck::Dummy> wrapping a protobuf message with tonic::Request. The message can be retrieved with into_inner().

Response is a Result type that returns tonic::Response or tonic::Status, such as Result<tonic::Response<example::duck::Dummy, tonic::Status>.

Build script

Tonic expects a flow to compile protobuf into rust code when running cargo build. Therefore, put the following build.rs in the project root.

fn main() -> Result<(), Box<dyn std::error::Error>> {
    tonic_build::compile_protos("proto/example_duck.proto")?;
    Ok(())
}

Note that the tonic-build crate is required for protobuf compilation, so add it to the build-dependencies of Cargo.toml.

[build-dependencies]
tonic-build	=  { version = "0.4", features = ["prost"] }
⁋ May 17, 2021↻ May 23, 2022