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↻ Dec 18, 2024
中馬崇尋
Chuma Takahiro