Calling from a gRPC Client
Consume the service.
Calling from a gRPC Client is a free Learn Rust Coding lesson on CoddyKit — lesson 4 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.
The Generated Client
For each service tonic generates a client struct, for example GreeterClient, in the greeter_client module. It exposes one async method per rpc.
You construct it from a transport channel or by connecting directly to an endpoint.
use greeter::v1::greeter_client::GreeterClient;
use greeter::v1::HelloRequest;Connecting to a Server
The simplest path is GreeterClient::connect, which takes an address string and returns a connected client.
It runs inside an async context, so call it under #[tokio::main] with .await.
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = GreeterClient::connect("http://[::1]:50051").await?;
Ok(())
}Making a Unary Call
Wrap your message in a tonic::Request (or use Request::new) and call the generated method.
The response is a tonic::Response; call .into_inner() to read the message.
let request = tonic::Request::new(HelloRequest { name: "Ada".into() });
let response = client.say_hello(request).await?;
println!("{}", response.into_inner().message);Handling Status Errors
If the server returns an error, the call resolves to Err(Status). Inspect status.code() and status.message() to react.
This mirrors the server side: codes like NotFound or Unauthenticated travel back to the client.
match client.say_hello(req).await {
Ok(resp) => println!("{}", resp.into_inner().message),
Err(status) => eprintln!("{}: {}", status.code(), status.message()),
}Building a Channel
For reuse and configuration, build a Channel explicitly with Endpoint. You can set timeouts, TCP keepalive, and connection options.
Then construct the client with GreeterClient::new(channel).
use tonic::transport::{Channel, Endpoint};
let channel = Endpoint::from_static("http://[::1]:50051")
.timeout(std::time::Duration::from_secs(5))
.connect()
.await?;
let mut client = GreeterClient::new(channel);Sending Metadata
Attach headers such as auth tokens by inserting into the request metadata before sending.
Use MetadataValue for the value; it must be a valid ASCII header value.
use tonic::metadata::MetadataValue;
let mut req = tonic::Request::new(HelloRequest { name: "Ada".into() });
let token: MetadataValue<_> = "Bearer abc123".parse()?;
req.metadata_mut().insert("authorization", token);Per-Call Deadlines
Set a deadline so a slow server does not hang the client. set_timeout on the request aborts it with a DeadlineExceeded status if exceeded.
Deadlines propagate to the server, which can stop work early.
let mut req = tonic::Request::new(HelloRequest { name: "Ada".into() });
req.set_timeout(std::time::Duration::from_secs(2));
let resp = client.say_hello(req).await?;Consuming a Server Stream
A server-streaming call returns a stream. Take it with into_inner() and pull messages with message().await in a loop until it yields None.
Each iteration gives one decoded reply.
let mut stream = client.server_stream(req).await?.into_inner();
while let Some(item) = stream.message().await? {
println!("{:?}", item);
}Client Streaming
For a client-streaming call, pass an async stream of requests. Wrap an iterator or channel with tokio_stream and hand it to the method.
The single response arrives after you finish sending.
use tokio_stream::iter;
let outbound = iter(vec![msg1, msg2, msg3]);
let response = client.client_stream(Request::new(outbound)).await?;
println!("{:?}", response.into_inner());TLS Connections
For encrypted transport, configure a ClientTlsConfig with a CA certificate and the server domain, then connect over https.
This requires the tls feature on the tonic dependency.
use tonic::transport::{ClientTlsConfig, Endpoint};
let tls = ClientTlsConfig::new().domain_name("example.com");
let channel = Endpoint::from_static("https://example.com:50051")
.tls_config(tls)?
.connect()
.await?;Reusing the Client
The underlying Channel is cheap to clone and multiplexes requests over one HTTP/2 connection. Clone the client across tasks rather than reconnecting.
This keeps connection setup costs low under concurrency.
let client = GreeterClient::new(channel);
let mut c1 = client.clone();
let mut c2 = client.clone();
// use c1 and c2 in separate tokio tasksQuick Check
How do you read the result of a unary client call in tonic?
Recap
You connected a generated client, made unary calls, handled Status errors, built configured channels, sent metadata, set deadlines, consumed server and client streams, enabled TLS, and reused cheaply cloned clients.
You can now build complete tonic-based gRPC services end to end.
Frequently asked questions
Is the “Calling from a gRPC Client” lesson free?
Yes — the full text of “Calling from a gRPC Client” 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 “Calling from a gRPC Client”?
Consume the service. 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 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Calling from a gRPC Client” 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