Protobuf and Service Definitions
Describe your API in proto.
Protobuf and Service Definitions is a free Learn Rust Coding lesson on CoddyKit — lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Learn Rust Coding learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Why gRPC and Protobuf
gRPC is a high-performance RPC framework built on HTTP/2 and Protocol Buffers. In Rust, the tonic crate implements gRPC end to end.
Protobuf is the interface definition language (IDL). You describe messages and services once in a .proto file, and code generators produce strongly typed client and server stubs.
Anatomy of a .proto File
Every proto file declares a syntax version and a package. The package namespaces generated types and avoids collisions.
Use proto3 for tonic. The package name maps to a Rust module path after generation.
syntax = "proto3";
package greeter.v1;Defining Messages
A message is a typed record. Each field has a type, a name, and a unique field number used for wire encoding.
Field numbers must be stable: never reuse or renumber a field once data exists, or you break compatibility.
message HelloRequest {
string name = 1;
int32 age = 2;
}Scalar Types and Rust Mapping
Protobuf scalars map to Rust types via prost. string becomes String, int32 becomes i32, bool becomes bool, and bytes becomes Vec<u8>.
In proto3 every scalar has a default (empty string, 0, false); they are not optional unless marked.
message Metric {
string label = 1;
double value = 2;
bool active = 3;
}Defining a Service
A service groups RPC methods. Each rpc declares a method name, a request message, and a response message.
tonic generates a server trait and a client struct from this block. Implementing the trait is how you provide behavior.
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloReply {
string message = 1;
}Four RPC Method Kinds
gRPC supports four streaming shapes: unary, server streaming, client streaming, and bidirectional streaming.
You signal a stream with the stream keyword on the request or response side, or both.
service Chat {
rpc Unary (Msg) returns (Msg);
rpc ServerStream (Msg) returns (stream Msg);
rpc ClientStream (stream Msg) returns (Msg);
rpc BiDi (stream Msg) returns (stream Msg);
}Enums in Protobuf
Enums are integer-backed. In proto3 the first value must be numbered 0 and acts as the default.
prost generates a Rust enum plus helpers to convert from the underlying i32, since unknown values can arrive over the wire.
enum Status {
STATUS_UNKNOWN = 0;
STATUS_ACTIVE = 1;
STATUS_BANNED = 2;
}Nested and Repeated Fields
A repeated field is a list and maps to Vec<T> in Rust. Messages can be nested or referenced by name.
This lets you model collections and composite payloads without extra ceremony.
message Order {
string id = 1;
repeated Item items = 2;
}
message Item {
string sku = 1;
int32 qty = 2;
}The Empty and Well-Known Types
For methods that take or return nothing, import google/protobuf/empty.proto and use Empty.
Other well-known types include Timestamp and Duration. tonic ships these definitions so you can import them in your build.
import "google/protobuf/empty.proto";
service Health {
rpc Ping (google.protobuf.Empty) returns (google.protobuf.Empty);
}Versioning with Packages
Putting a version in the package, like greeter.v1, lets you evolve an API safely. A breaking change goes into greeter.v2 while v1 keeps serving.
This convention keeps the generated Rust modules clean: greeter::v1 and greeter::v2 coexist.
package greeter.v1;
// later, a parallel file:
// package greeter.v2;Field Compatibility Rules
Adding a new field with a fresh number is backward compatible; old clients ignore it. Removing a field is risky unless you reserve its number and name.
Reserving prevents anyone from reusing a retired field number and corrupting decoding.
message User {
reserved 3, 5;
reserved "legacy_token";
string id = 1;
string email = 2;
}Quick Check
Test your understanding of proto3 service definitions.
Recap
You defined services and messages in proto3: stable field numbers, scalar-to-Rust mappings, enums, repeated and nested fields, the four RPC shapes, well-known types, and versioning via packages.
Next you will turn these definitions into Rust code with tonic-build.
Frequently asked questions
Is the “Protobuf and Service Definitions” lesson free?
Yes — the full text of “Protobuf and Service Definitions” is free to read here on the web, and the Learn Rust Coding course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Learn Rust Coding course, upgrade to CoddyKit PRO.
What will I learn in “Protobuf and Service Definitions”?
Describe your API in proto. You practise Learn Rust Coding with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Learn Rust Coding?
No prior experience is required. Learn Rust Coding on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Protobuf and Service Definitions” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Learn Rust Coding lesson?
Yes. Every Learn Rust Coding lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Protobuf and Service Definitions
- Generating Code with tonic-build
- Implementing a gRPC Server
- Calling from a gRPC Client