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