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"] }