Rustgrpc

Rustgrpc

Using gRPC in Rust, while learning the basics of Tonic and protobuffers.

Well what is a protobuf?

Protobuffers are a way of encoding structured data in a text format, used in many different programming languages. They are a popular alternative to JSON and YAML, which are used in REST APIs.

According to Google:

Protocol buffers are a Language-Neutral, platform-neutral, Protobuf is a data interchange format and language for structured data. It’s like JSON, but smaller and faster.

Protobuf Syntax overview

When defining fields in .proto files, it is possible to set if the field is optional or not, or repeated. A field can also be:

  • message
  • enum
  • oneof
  • map

One basic example is:

message User {
  int64 id = 1;
  string name = 2;
}

Implementing a basic example: “GreetingRust”

  1. Create a new project with cargo
cargo new GreetingRust
  1. Add the following dependencies
cargo add tonic
  1. Create the .proto inside a folder
mkdir src
touch src/greet.proto
  1. Add the .proto file
syntax = "proto3";

import "greet.proto";

service GreetService {
  rpc Greet (GreetRequest) returns (GreetResponse);
}
  1. Create the src/greet.proto file
syntax = "proto3";
message GreetRequest {
  string name = 1;
}
message GreetResponse {
  string message = 1;
}
  1. Create the src/greet.rs file
use tonic::transport::Server;
use tonic::{Request, Response, Status};
use greet::greet_server::{Greet, GreetServer};
use greet::GreetRequest;
use greet::GreetResponse;

#[derive(Debug)]
pub struct MyGreet {}

#[tonic::async_trait]
impl Greet for MyGreet {
    async fn greet(&self, request: Request<GreetRequest>) -> Result<Response<GreetResponse>, Status> {
        println!("Got a request: {:?}", request);
        let response = GreetResponse {
            message: format!("Hello {}!", request.into_inner().name),
        };
        Ok(Response::new(response))
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let addr = "[::1]:50051".parse()?;
    let greeter = MyGreet {};
    Server::builder()
        .add_service(GreetServer::new(greeter))
        .serve(addr)
        .await?;
    Ok(())
}
  1. Run the code
cargo run
  1. Create a client and send a request
use greet::greet_client::GreetClient;
use greet::GreetRequest;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut client = GreetClient::connect("http://[::1]:50051").await?;
    let request = tonic::Request::new(GreetRequest {
        name: "Diogo".to_string(),
    });
    let response = client.greet(request).await?;
    println!("RESPONSE={:?}", response);
    Ok(())
}

source code

code protobuf overview

0%