|
| 1 | +# Generate Code from Proto Files |
| 2 | + |
| 3 | +This is a tutorial for generating code from Proto files using gRPC-Rust. This tutorial will utilize the RouteGuide example. |
| 4 | + |
| 5 | +### Prerequisites |
| 6 | + |
| 7 | +* [**Tonic**](https://github.com/hyperium/tonic.git), the open source repository that gRPC-Rust is build off on |
| 8 | +```sh |
| 9 | +$ git clone https://github.com/hyperium/tonic.git |
| 10 | +``` |
| 11 | +* [**Rust**](https://www.rust-lang.org/). |
| 12 | + * Follow installation instructions [here](https://www.rust-lang.org/tools/install). |
| 13 | +* [**Bazel 8.3.1**](https://bazel.build/). |
| 14 | + * Follow installation instructions [here](https://github.com/bazelbuild/bazel/releases). |
| 15 | +* [**Protocol buffer**](https://developers.google.com/protocol-buffers) **compiler**, `protoc`, [version 3](https://protobuf.dev/programming-guides/proto3). |
| 16 | + * For installation instructions, see [Protocol Buffer Compiler Installation](https://grpc.io/docs/protoc-installation/). |
| 17 | + * NOTE: Must need a version of Protoc 3.31.1 or higher. |
| 18 | +* **Rust plugins** for the protocol compiler: |
| 19 | +```sh |
| 20 | +$ cd tonic/protoc-gen-rust-grpc |
| 21 | +$ bazel build //src:protoc-gen-rust-grpc |
| 22 | +$ PLUGIN_PATH="$(pwd)/bazel-bin/src/protoc-gen-rust-grpc" |
| 23 | +``` |
| 24 | + |
| 25 | +* Update your PATH so that the protoc compiler can find the plugins: |
| 26 | + |
| 27 | +```sh |
| 28 | +export PATH="$(pwd)/bazel-bin/src/:$PATH" |
| 29 | +``` |
| 30 | + |
| 31 | +## Generating client and server code |
| 32 | + |
| 33 | +Next we need to generate the gRPC client and server interfaces from our `.proto` |
| 34 | +service definition. |
| 35 | + |
| 36 | +### Dependencies |
| 37 | +Edit `Cargo.toml` and add the dependency we'll need for this example, which is tonic-protobuf-build: |
| 38 | + |
| 39 | +```console |
| 40 | +cargo add tonic-protobuf-build |
| 41 | +``` |
| 42 | + |
| 43 | +### Compiling and Building Proto |
| 44 | +Create a `build.rs` file at the root of your crate. A build.rs script is a Rust program that Cargo executes before compiling your main project. Its purpose is to perform tasks like generating source code, linking to non-Rust libraries, or setting environment variables that influence the build process. |
| 45 | + |
| 46 | +In this case, we will be putting the command to compile and build the `.proto` file in build.rs. We will use gRPC's tonic_protobuf_build crate to generate code from the `.proto` file. |
| 47 | +```rust |
| 48 | +fn main() { |
| 49 | + tonic_protobuf_build::CodeGen::new() |
| 50 | + .include("proto") |
| 51 | + .inputs(["routeguide.proto"]) |
| 52 | + .output_dir("generated") |
| 53 | + .compile() |
| 54 | + .unwrap(); |
| 55 | +} |
| 56 | +``` |
| 57 | +Now, run |
| 58 | +```shell |
| 59 | +$ cargo build |
| 60 | +``` |
| 61 | + |
| 62 | +That's it. The generated code contains: |
| 63 | + |
| 64 | +- Struct definitions for message types `Point` and `Feature`. |
| 65 | +- A service trait we'll need to implement: `route_guide_server::RouteGuide`. |
| 66 | +- A client type we'll use to call the server: `route_guide_client::RouteGuideClient<T>`. |
| 67 | + |
| 68 | +If your are curious as to where the generated files are, keep reading. The mystery will be revealed |
| 69 | +soon! We can now move on to the fun part. |
| 70 | + |
| 71 | +## Bringing Generated Code into Scope |
| 72 | + |
| 73 | +The generated code is placed inside our target directory, in a location defined by the `OUT_DIR` |
| 74 | +environment variable that is set by cargo. For our example, this means you can find the generated |
| 75 | +code in a path similar to `target/debug/build/routeguide/out/routeguide.rs`. |
| 76 | + |
| 77 | +We can use gRPC's `include_proto` macro to bring the generated code into scope: |
| 78 | + |
| 79 | +```rust |
| 80 | +pub mod routeguide { |
| 81 | + tonic::include_proto!("routeguide"); |
| 82 | +} |
| 83 | +``` |
| 84 | + |
| 85 | +**Note**: The token passed to the `include_proto` macro (in our case "routeguide") is the name of |
| 86 | +the package declared in our `.proto` file, not a filename, e.g "routeguide.rs". |
| 87 | + |
| 88 | +With this in place, we can stub out our service implementation: |
| 89 | + |
0 commit comments