Cómo usar gRPC con Rust Tonic y Postgres con ejemplos
Tags: rust, tutorial, beginners, postgres
Published: 2022-06-11 19:12:59

<!--
    Post{
        subtitle: "Learn how to use Tonic to use gRPC in Rust with CRUD examples"
        image: "posts/web/tonic.png",
        image_decription: "Image from the official website",
        tags: "gRPC Tonic Rust How",
    }
-->

<!-- Link -->

[Steadylearner]: https://www.steadylearner.com
[Rust Website]: https://www.rust-lang.org/

[Rust Rocket]: https://rocket.rs/
[Rocket Getting Started]: https://rocket.rs/v0.4/guide/getting-started
[Rocket JSON Example]: https://github.com/SergioBenitez/Rocket/tree/master/examples/json
[Redirect]: https://api.rocket.rs/v0.4/rocket/response/struct.Redirect.html
[Tera]: https://tera.netlify.com/
[Rocket Tera example]: https://github.com/SergioBenitez/Rocket/tree/master/examples/tera_templates

[CORS]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
[OPTIONS]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS
[Rocket CORS]: https://github.com/lawliet89/rocket_cors
[Rocket CORS examples]: https://github.com/lawliet89/rocket_cors/tree/master/examples
[Rocket CORS fairing example]: https://github.com/lawliet89/rocket_cors/blob/master/examples/fairing.rs
[Rocket CORS fairng test example]: https://github.com/lawliet89/rocket_cors/blob/master/tests/fairing.rs

[Rust Yew Examples]: https://github.com/yewstack/yew/tree/master/examples

[hyper]: https://github.com/hyperium/hyper

[Rust Dotenv]: https://crates.io/crates/dotenv
[Reqwest]: https://docs.rs/reqwest/0.9.18/reqwest/

[stdweb]: https://github.com/koute/stdweb

[YouTube API]: https://developers.google.com/youtube/v3/getting-started#before-you-start
[How to use YouTube API for developers]: https://www.google.com/search?q=how+to+use+youtube+api+for+developers

[Rust Full Stack]: https://github.com/steadylearner/Rust-Full-Stack
[JSON Webservice]: https://github.com/steadylearner/Rust-Full-Stack/tree/master/before/JSON_Webservice

[Rust Blog Example]: https://github.com/steadylearner/Rust-Full-Stack/tree/master/web/before/rust_blog

[CRA]: https://github.com/facebook/create-react-app

[protocol buffers]: https://developers.google.com/protocol-buffers/docs/overview
[Tonic]: https://github.com/hyperium/tonic
[Rust Postgresql]: https://github.com/sfackler/rust-postgres
[Rust Postgresql query]: https://docs.rs/postgres/0.15.2/postgres/struct.Connection.html#method.query
[Rust Postgresql execute]: https://docs.rs/postgres/0.15.2/postgres/struct.Connection.html#method.execute
[Tonic CRUD Example by Steadylearner]: https://github.com/steadylearner/Rust-Full-Stack/tree/master/gRPC/rust/user
[Official Tonic Guide]: https://github.com/hyperium/tonic/blob/master/examples/helloworld-tutorial.md
[gRPC Client]: https://github.com/uw-labs/bloomrpc

[How to install Postgresql]: https://www.digitalocean.com/community/tutorials/how-to-install-and-use-postgresql-on-ubuntu-18-04

[tonic-build]: https://github.com/hyperium/tonic/blob/master/tonic-build/README.md

[Rust uuid]: https://crates.io/crates/uuid
[chrono]: https://docs.rs/chrono/0.4.9/chrono/

[graphiql]: https://github.com/graphql/graphiql

<!-- / -->

<!-- Steadylearner Post -->

[Rust blog posts]: https://www.steadylearner.com/blog/search/Rust
[How to install Rust]: https://www.steadylearner.com/blog/read/How-to-install-Rust
[Rust Chat App]: https://www.steadylearner.com/blog/read/How-to-start-Rust-Chat-App
[Rust Yew Frontend]: https://github.com/yewstack/yew
[Yew Counter]: https://www.steadylearner.com/yew_counter
[How to use Rust Yew]: https://www.steadylearner.com/blog/read/How-to-use-Rust-Yew
[How to deploy Rust Web App]: https://www.steadylearner.com/blog/read/How-to-deploy-Rust-Web-App
[How to start Rust Chat App]: https://www.steadylearner.com/blog/read/How-to-start-Rust-Chat-App
[Fullstack Rust with Yew]: https://www.steadylearner.com/blog/read/Fullstack-Rust-with-Yew
[How to use NPM packages with Rust Frontend]: https://www.steadylearner.com/blog/read/How-to-use-NPM-packages-with-Rust-Frontend
[How to use markdown with code snippets in Rust Yew Frontend]: https://www.steadylearner.com/blog/read/How-to-use-markdown-with-code-snippets-in-Rust-Yew-Frontend
[How to modulize your Rust Frontend]: https://www.steadylearner.com/blog/read/How-to-modulize-your-Rust-Frontend
[How to write Full Stack Rust Code]: https://www.steadylearner.com/blog/read/How-to-write-Full-Stack-Rust-code
[How to use a modal in Rust]: https://www.steadylearner.com/blog/read/How-to-use-a-modal-in-Rust
[How to use routers in Rust Frontend]: https://www.steadylearner.com/blog/read/How-to-use-routers-in-Rust-Frontend
[How to serve static files with Rust]: https://www.steadylearner.com/blog/read/How-to-serve-static-files-with-Rust
[How to use a single page app wtih Rust]: https://www.steadylearner.com/blog/read/How-to-use-a-single-page-app-with-Rust
[How to use Rust Tera for undefined paths]: https://www.steadylearner.com/blog/read/How-to-use-Rust-Tera-for-undefined-paths
[How to make JSON Webservice with Rust and YouTube API]: https://www.steadylearner.com/blog/read/How-to-make-JSON-Webservice-with-Rust-and-YouTube-API
[How to use CORS and OPTIONS HTTP request with Rust Rocket]: https://www.steadylearner.com/blog/read/How-to-use-CORS-and-OPTIONS-HTTP-request-with-Rust-Rocket
[How to render a YouTube vlog with Rust Yew fetch API]: https://www.steadylearner.com/blog/read/How-to-render-a-YouTube-vlog-with-Rust-Yew-fetch-API

[How to use Python in JavaScript]: https://www.steadylearner.com/blog/read/How-to-use-Python-in-JavaScript
[How to use React Spring to animate your message]: https://medium.com/@steadylearner/how-to-use-react-spring-to-animate-your-message-2bd2a7e62a5a

<!-- / -->

<!-- Steadylearner Twitter and LinkedIn  -->

[Twitter]: https://twitter.com/steadylearner_p
[LinkedIn]: https://www.linkedin.com/in/steady-learner-3151b7164/

<!--  -->

En este post aprendermos a usar Rust, [Tonic] y la crate gRPC, y implementaremos un CRUD con [Postgresql database][Rust Postgresql].

[Puedes contactarme por Telegram si necesitas contratar a un desarrollador Blockchain Full Stack.](https://t.me/steadylearner)

[También puedes unirte a mi grupo de telegram, en el cual puedes encontrar otros desarrolladores blockchain, así como reclutadores, jefes de proyecto, así como hacer preguntas y hacer conexiones.](https://t.me/solanadevelopers)

El propósito de este post es poder ayudarte trabajar con Rust Tonic y que puedas empezar a programar tu propio proyecto.

<br />

<h2 class="red-white">Prerequisítos</h2>

1. ¿[Qué es gRPC](https://grpc.io/docs/guides/) y buffers de protocolo?
2. Rust, Postgresql (u otras bases de datos)
3. Guía oficial de Tonic
4. Cliente gRPC

---

Si no tienes instalado Rust en tu eqipo, lee [Como instalar Rust](https://www.steadylearner.com/blog/read/How-to-install-Rust). Usaremos el crate Rust Postgresql para este post. [Deberías instalar Postgresql](https://www.digitalocean.com/community/tutorials/how-to-install-and-use-postgresql-on-ubuntu-18-04) en caso de que no lo hayas hecho aún.

Asumiré que ya estas familiarizado con gRPC, Rust y la base de datos Postgresql. De lo contrario por favor lee la documentación antes de empezar.

Puede que no necesites [el cliente gRPC](https://github.com/uw-labs/bloomrpc). Pero lo dejaré aquí antes del resto del contenido, porque es muy útil y ademas toma mucho tiempo para instalarse. Para ahorrarte tiempo te dejaré [las instrucciones](https://github.com/uw-labs/bloomrpc#installation).

<br />

<h2 class="blue">Tabla de Contenido.</h2>

1. Configuración del proyecto
2. Definir el servicio gRPC para el CRUD
3. Preparar nuestro Cargo.toml para instalar dependencias
4. Hacer el server gRPC con Tonic
5. Implementar el servicio gRPC de el CRUD con Rust Postgresql
6. Usar el cliente gRPC para probarlo
7. Conclusión

---

Reusé algunas parte de [la guía oficial de Tonic](https://github.com/hyperium/tonic/blob/master/examples/helloworld-tutorial.md) para hacer funcionar el flujo de forma similar. Esto va a ayudar a que entiendas el post mejor.

[Puedes encontrar el código fuente aquí](https://github.com/steadylearner/Rust-Full-Stack/tree/master/gRPC)

<br />

## 1. Configuración del Proyecto

Lo primero que haremos será configurar los datos para la base de datos. Espero que ya tengas instalado alguna base de datos SQL en tu equipo. [Puedes consultar estos comandos SQL](https://www.linode.com/docs/databases/postgresql/how-to-back-up-your-postgresql-database/).

Puedes llamar a tu base de datos como desees.

```sql
CREATE DATABASE grpc OWNER you;
\c grpc;
```

Luego escribe, **$psql users < users.sql** o pegalos manualmente en l consola psql después de autenticarte.

```sql
-- users.sql
CREATE TABLE users(
  id VARCHAR(255) PRIMARY KEY,
  first_name VARCHAR(255) NOT NULL,
  last_name VARCHAR(255) NOT NULL,
  date_of_birth Date NOT NULL
);

INSERT INTO users VALUES
   ('steadylearner', 'steady', 'learner', 'yours');
INSERT INTO users VALUES
    ('mybirthdayisblackfriday', 'mybirthdayis', 'blackfriday', '2019-11-25');
INSERT INTO users VALUES
    ('mybirthdayisnotblackfriday', 'mybirthdayis', 'notblackfriday', '2019-11-26');
```

Luego puedes guardar esos datos desde Postgresql con **$pg_dump users > users.sql**.

La Configuración de la base de datos esta lista. Ahora crea un nuevo proyecto de Rust para usarla y aprender a usar [Tonic](https://github.com/hyperium/tonic).

```console
$cargo new user
$cd user
```

Crea un archivo .env en la carpeta para proteger tu base de datos y la información de login.Guiate con este comando.

```console
$echo DATABASE_URL=postgres://postgres:postgres@localhost/grpc > .env
```

<br />

## 2. Definir el servicio gRPC para el CRUD

Preparamos una configuración mínima para este post en la sección pasada. Ahora definiremos el servicio gRPC con el método request y response. Haremos uso de los buffers de protocolo para usar los datos que hicimos con Postgresql.

Crearemos los archivos .proto en la carpeta **proto**. Usa estos comandos.

```console
$mkdir proto
$touch proto/user.proto
```

Primero definiremos el nombre de nuestro paquete, el cual es el que Tonic usa incluyendo los protos en las aplicaciones de cliente y servidor. En este caso será **user**.

```proto
syntax = "proto3";
package user;
```

Ahora definiremos nuestro servicio CRUD. Este servicio va a contener las llamadas actuales gRPC. Las usaremos para crear el ejemplo de CRUD de Rust con Tonic.

```proto
service Crud { // Use whatever name you want, this is for blog posts and not prouction files.
  rpc GetUser (UserRequest) returns (UserReply) {} // becomes get_user in impl functions in Rust files
  rpc ListUsers(Empty) returns (Users) {}
  rpc CreateUser (CreateUserRequest) returns (CreateUserReply) {}
  rpc UpdateUser (UpdateUserRequest) returns (UpdateUserReply) {}
  rpc DeleteUser (UserRequest) returns (DeleteUserReply) {}
  rpc DeleteUsers (Empty) returns (DeleteUserReply) {}
}
```

Nada complicado de momento. Se que es un poco verboso pero, es para hacerlo mas explícito y fácil separando la lógica.

Si Tienes una mejor manera de hacerlo o si tienes más experiencia con gRPC no dudes en contactarme por [Twitter](https://twitter.com/steadylearner_p) o también podrías crear un issue en Github.

Finalmente especificaremos los tipos que usamos en el método RPC de nuestro **CRUD**. Los tipos RPC son definidos como mensajes que contienen campos por tipo. Algo similar a esto.

```proto
message Empty {}

message UserRequest {
    string id = 1;
}

message UserReply {
    string id = 1;
    string first_name = 2;
    string last_name = 3;
    string date_of_birth = 4;
}

message CreateUserRequest {
    string first_name = 1;
    string last_name = 2;
    string date_of_birth = 3;
}

message CreateUserReply {
    string message = 1;
}

message UpdateUserRequest {
    string id = 1;
    string first_name = 2;
    string last_name = 3;
    string date_of_birth = 4;
}

message UpdateUserReply {
    string message = 1;
}

message DeleteUserReply {
    string message = 1;
}

message Users {
    repeated UserReply users = 1;
}
```

Puedes ver que usé tipo **string** para **date_of_birth** en lugar de **date**. Lo hice porque no podía encontrar el ejemplo correcto para el tipo **DATE** en protobuf y hacerlo funcionar con [Tonic](https://github.com/hyperium/tonic),[Buffers de protocolo](https://developers.google.com/protocol-buffers/docs/overview) y el sistema de tipos de Rust.

Si eres un experto con esto, o tienes más experiencia para hacerlo de una mejor manera, agradecería que me ayudes a corregir esto.

Al terminar nuestro archivo **.proto** de nuestro CRUD debería verse similar a este.

```proto
// user.proto
syntax = "proto3";

package user;

service Crud {
  rpc GetUser (UserRequest) returns (UserReply) {}
  rpc ListUsers(Empty) returns (Users) {}
  rpc CreateUser (CreateUserRequest) returns (CreateUserReply) {}
  rpc UpdateUser (UpdateUserRequest) returns (UpdateUserReply) {}
  rpc DeleteUser (UserRequest) returns (DeleteUserReply) {}
  rpc DeleteUsers (Empty) returns (DeleteUserReply) {}
}

message Empty {}

message UserRequest {
    string id = 1;
}

message UserReply {
    string id = 1;
    string first_name = 2;
    string last_name = 3;
    string date_of_birth = 4;
}

message CreateUserRequest {
    string first_name = 1;
    string last_name = 2;
    string date_of_birth = 3;
}

message CreateUserReply {
    string message = 1;
}

message UpdateUserRequest {
    string id = 1;
    string first_name = 2;
    string last_name = 3;
    string date_of_birth = 4;
}

message UpdateUserReply {
    string message = 1;
}

message DeleteUserReply {
    string message = 1;
}

message Users {
    repeated UserReply users = 1;
}
```

Encontré que trabajar con Rust no es fácil y se vuelve cada vez mas difícil de compilarlo sin errores cuando queremos especificar los tipos de datos de [buffers de protocolo](https://developers.google.com/protocol-buffers/docs/overview) y [Rust Postgresql](https://github.com/sfackler/rust-postgres) al mismo tiempo.

Si deseas hacer tu propio proyecto de Rust Tonic con otros archivos proto. primero compila [Tonic CRUD Example por Steadylearner](https://github.com/steadylearner/Rust-Full-Stack/tree/master/gRPC/rust/user) para poder recolectar los archivos binarios y poder empezar editando de a pequeñas partes el código de Rust y las definiciones de protbuf que estan allí.

<br />

## 3. Preparar nuestro Cargo.toml para instalar dependencias

Configuramos el proyecto e hicimos el archivo protobuf para usar gRPC con Rust. Por lo tanto ya podemos escribir el código para de Rust con Tonic.

Lo primero será preparar las dependencias con `Cargo.toml` .

```toml
[package]
name = "rust-tonic-crud-example"
version = "0.1.0"
authors = ["www.steadylearner.com"]
edition = "2018"

[dependencies]
tonic = { version = "0.1.0-alpha.4", features = ["rustls"] }
bytes = "0.4"
prost = "0.5"
prost-derive = "0.5"
prost-types = "0.5.0"
tokio = "=0.2.0-alpha.6"
futures-preview = { version = "=0.3.0-alpha.19", default-features = false, features = ["alloc"]}
async-stream = "0.1.2"
http = "0.1"
tower = "=0.3.0-alpha.2"
serde = "1.0.101"
serde_json = "1.0.41"
serde_derive = "1.0.101"
console = "0.9.0"
# Database(Postgresql)
postgres = { version = "0.15.2", features = ["with-chrono"] }
dotenv = "0.15.0"
chrono = "0.4.9"
uuid = { version = "0.8.1", features = ["serde", "v4"] }

# Help you use gRPC protobuf files in Rust.
[build-dependencies]
tonic-build = "0.1.0-alpha.4"
```

Hay muchas dependencias para este simple proyecto.
pero, si te fijas en esta parte se hará mas sencillo de entender.

```toml
# Database(Postgresql)
postgres = { version = "0.15.2", features = ["with-chrono"] }
dotenv = "0.15.0"
chrono = "0.4.9"
uuid = { version = "0.8.1", features = ["serde", "v4"] }
```

Ese bloque corresponde a [Rust Postgresql](https://github.com/sfackler/rust-postgres) y el resto para [Tonic](https://github.com/hyperium/tonic).

incluimos `tonic-build` para hacer nuestro código gRPC del cliente y servidor.

Si no has usado gRPC o Tonic puede que te confundas.
Pero, todos los lenguajes que usan gRPC tienen un proceso similar para usar las definiciones proto buffer con ellos.

Con Rust Tonic debemos incluirlo en el proceso `build` de nuestra aplicación. Lo configuráremos con **build.rs** en la raíz del crate.

```rs
fn main() -> Result<(), Box<dyn std::error::Error>> {
    tonic_build::compile_protos("proto/user.proto")?;
    Ok(())
}
```

Nada complicado de momento, solo necesitas modificar el nombre del archvio de otros ejemplos. De esta manera **tonic-build** compilará los archivos **protobufs** para que funcionen con los proyectos de Rust que integren gRPC.

Automáticamente creará algunos módulos de Rust para que puedas usarlos luego en tu código Rust dependiedo de las definiciones de los protobuf que hayas usado en los archivos protobuf. Puedes verificar esto con el código Rust que leeras dentro de poco.

Si deseas mas detalles, por favor consulta [tonic-build](https://github.com/hyperium/tonic/blob/master/tonic-build/README.md).

<br />

## 4. Hacer el server gRPC con Tonic

El proceso de preparación terminó en la parte pasada.
Finalmente Escribiremos nuestro código Rust, Empezando a construir el servidor Rust Tonic gRPC, de la siguiente manera.

```rs
// main.rs
extern crate postgres;
extern crate dotenv;

extern crate chrono;

// 1.
pub mod user {
    tonic::include_proto!("user");
}

use tonic::{transport::Server};

// 1.
use user::{
    server::{CrudServer},
};

extern crate uuid;

extern crate console;
use console::Style;

mod db_connection; // 2.

mod service;
use crate::service::User;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let addr = "[::1]:50051".parse().unwrap(); // 3.
    let user = User::default();

    let blue = Style::new()
        .blue();

    println!("\nRust gRPC Server ready at {}", blue.apply_to(addr)); // 4.

    Server::builder().serve(addr, CrudServer::new(user)).await?;
    Ok(())
}
```

Esto será el punto de entrada cuando arranquemos nuestro servidor. [La mayoria es para definir dependencias y módulos que usaremos](https://www.steadylearner.com/blog/read/How-to-modulize-your-Rust-Frontend).

El archivo es sencillo pero tiene unos puntos que debes entender.

**1.** Aquí es donde podremos usar los código autogenerados de **tonic_build::compile_protos("proto/user.proto")?;** y **tonic-build = "0.1.0-alpha.4"**.

Puedes usar módulos hechos de forma similar a esta, así como handlers que crearemos con **models.rs**.

```rs
use user::{
    server::{CrudServer},
};
```

**2.** El contenido del archivo `db_connection` debe ser similar a este.

```rs
use postgres::{Connection, TlsMode};
use dotenv::dotenv;
use std::env;

pub fn establish_connection() -> Connection {
    dotenv().ok();
    let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    Connection::connect(database_url, TlsMode::None).unwrap()
}
```

Puede ser reusado sin necesidad de modificarlo, lo separeremos en una función y lo llamaremos desde donde queramos.

**3.** Este es código de los creadores de [Tonic](https://github.com/hyperium/tonic). Deberías usarlo sin el prefijo de HTTP cuando uses CURL y [el cliente gRPC](https://github.com/uw-labs/bloomrpc).

**4.** Estamos usando **console::Style;** con `println!` para visitar fácilmente el servidor con exploradores y poder enviar comandos CURL.

<br />

## 5. Implementar el servicio gRPC de el CRUD con Rust Postgresql

En esta parte crearemos algunos handlers en **service.rs** mientras seguimos la definiciones que hicimos en el archivo **user.proto**. El resto del código será similar a esto.

El siguiente bloque es largo. Este bloque es para implemntar todas las operaciones del CRUD de gRPC con la base de datos Postgresql. Lee las partes que te interesen.

```rs
use chrono::*;
use uuid::Uuid;

use crate::db_connection::establish_connection;

use tonic::{Request, Response, Status};

// Compare it with user.proto file, imported from the main.rs file
use crate::user::{
    server::Crud, CreateUserReply, CreateUserRequest, DeleteUserReply, Empty, UpdateUserReply,
    UpdateUserRequest, UserReply, UserRequest, Users,
};

#[derive(Default)]
pub struct User {}

#[tonic::async_trait]
impl Crud for User {
    // Compare it with the Crud service definition in user.proto file
    // The method GetUser becomes get_user etc
    async fn get_user(&self, request: Request<UserRequest>) -> Result<Response<UserReply>, Status> {
        println!("Got a request: {:#?}", &request);
        // request is private, so use this instead to get the data in it.
        let UserRequest { id } = &request.into_inner();

        let conn = establish_connection();

        // 1.
        let rows = &conn
            .query("SELECT * FROM users WHERE id = $1", &[&id])
            .unwrap();

        // println!("{:#?}", rows);
        // println!("{:#?}", rows.get(0));
        // https://docs.rs/postgres/0.17.0-alpha.1/postgres/row/struct.Row.html

        let row = rows.get(0);
        println!("{:#?}", &row);

        // 2.
        let date_of_birth: NaiveDate = row.get(3);

        let reply = UserReply {
            id: row.get(0),
            first_name: row.get(1),
            last_name: row.get(2),
            // 2.
            date_of_birth: date_of_birth.to_string(),
        };

        Ok(Response::new(reply))
    }

    async fn list_users(&self, request: Request<Empty>) -> Result<Response<Users>, Status> {
        println!("Got a request: {:#?}", &request);
        let conn = establish_connection();

        // 3.
        let mut v: Vec<UserReply> = Vec::new();
        for row in &conn.query("SELECT * FROM users", &[]).unwrap() {
            let date_of_birth: NaiveDate = row.get(3);
            let user = UserReply {
                id: row.get(0),
                first_name: row.get(1),
                last_name: row.get(2),
                date_of_birth: date_of_birth.to_string(),
            };
            v.push(user);
        }

        let reply = Users { users: v };

        Ok(Response::new(reply))
    }

    // Test with create_users, Rust compiler shows errors to help you.
    async fn create_user(
        &self,
        request: Request<CreateUserRequest>,
    ) -> Result<Response<CreateUserReply>, Status> {
        println!("Got a request: {:#?}", &request);
        // 4.
        let user_id = Uuid::new_v4().to_hyphenated().to_string();
        let CreateUserRequest {
            first_name,
            last_name,
            date_of_birth,
        } = &request.into_inner();
        // 5.
        let serialize_date_of_birth = NaiveDate::parse_from_str(date_of_birth, "%Y-%m-%d").unwrap(); // String to Date

        let conn = establish_connection();
        // 6.
        let number_of_rows_affected = &conn.execute(
                "INSERT INTO users (id, first_name, last_name, date_of_birth) VALUES ($1, $2, $3, $4)",
                &[
                    &user_id,
                    &first_name,
                    &last_name,
                    &serialize_date_of_birth,
                ]
            )
            .unwrap();

        let reply = if number_of_rows_affected == &(0 as u64) {
            CreateUserReply {
                message: format!(
                    "Fail to create user with id {}.",
                    &user_id
                ),
            }
        } else {
            CreateUserReply {
                message: format!(
                    "Create {} user with id {}.",
                    &number_of_rows_affected, &user_id
                ),
            }
        };

        Ok(Response::new(reply))
    }

    async fn update_user(
        &self,
        request: Request<UpdateUserRequest>,
    ) -> Result<Response<UpdateUserReply>, Status> {
        println!("Got a request: {:#?}", &request);
        let UpdateUserRequest {
            id,
            first_name,
            last_name,
            date_of_birth,
        } = &request.into_inner();
        // 3.
        let serialize_date_of_birth = NaiveDate::parse_from_str(date_of_birth, "%Y-%m-%d").unwrap(); // String to Date

        let conn = establish_connection();

        let number_of_rows_affected = &conn
            .execute(
                "UPDATE users SET first_name = $2, last_name = $3, date_of_birth = $4 WHERE id = $1",
                &[
                    &id,
                    &first_name,
                    &last_name,
                    &serialize_date_of_birth,
                ]
            )
            .unwrap();

        let reply = if number_of_rows_affected == &(0 as u64) {
            UpdateUserReply {
                message: format!("Fail to update the user with id {}.", id),
            }
        } else {
            UpdateUserReply {
                message: format!("Update {} user with id {}", &number_of_rows_affected, &id),
            }
        };

        Ok(Response::new(reply))
    }

    async fn delete_user(
        &self,
        request: Request<UserRequest>,
    ) -> Result<Response<DeleteUserReply>, Status> {
        println!("Got a request: {:#?}", &request);
        let UserRequest { id } = &request.into_inner();
        let conn = establish_connection();

        let number_of_rows_affected = &conn
            .execute("DELETE FROM users WHERE id = $1", &[&id])
            .unwrap();

        let reply = if number_of_rows_affected == &(0 as u64) {
            DeleteUserReply {
                message: format!("Fail to delete the user with id {}.", id),
            }
        } else {
            DeleteUserReply {
                message: format!("Remove the user with id {}.", id),
            }
        };

        Ok(Response::new(reply))
    }

    async fn delete_users(
        &self,
        request: Request<Empty>,
    ) -> Result<Response<DeleteUserReply>, Status> {
        println!("Got a request: {:#?}", &request);
        let conn = establish_connection();

        let rows = &conn.query("DELETE FROM users", &[]).unwrap();

        let reply = DeleteUserReply {
            message: format!("Remove {} user data from the database.", rows.len()),
        };

        Ok(Response::new(reply))
    }
}
```

Como podrás observar hay muchas líneas de código, así que será un poco complicado para empezar. Quiero que pruebes este proyecto con las partes de **get_user** y **list_users**. De esa manera podrías mejorarlos y consultarlo añadiéndole comentarios.

**1.** Cuando leemos la documentación de [Rust Postgresql](https://github.com/sfackler/rust-postgres) nos damos cuenta de que tiene comandos de [execute](https://docs.rs/postgres/0.15.2/postgres/struct.Connection.html#method.execute) y [query](https://docs.rs/postgres/0.15.2/postgres/struct.Connection.html#method.query). La diferencia es que `execute` nos devuelve **el número de filas modificadas**, mientras `query` nos devuelve datos. Deberías poder encontrar cual usar dependiendo de la necesidad que tengas.

**2.** Cuando usas [Rust Postgresql](https://github.com/sfackler/rust-postgres) puede que te salte un error similar a este.

```console
cannot infer type
the trait `postgres::types::FromSql` is not implemented for
```

Si es así, debes cambiar el tipo [de la definición de datos para ayudar a que Rust sea compatible con postgresql](https://docs.rs/postgres/0.17.0-alpha.1/postgres/types/trait.FromSql.html#tymethod.from_sql) con [chrono](https://docs.rs/chrono/0.4.9/chrono/) .

```rs
let date_of_birth: NaiveDate = row.get(3);
```

Usamos el tipo de dato string para **date_of_birth** en el archivo **user.proto**. [Debemos modificarlo](https://docs.rs/postgres/0.17.0-alpha.1/postgres/types/trait.FromSql.html?search=to_string) de esta manera.

```rs
date_of_birth: date_of_birth.to_string(),
```

Este es el precio que debemos pagar para hacer funcionar Rust en conjunto con Postgresql y Protobuf. Puede que encuentres con una mejor manera de hacerlo.

**3.** Usamos la forma imperativa para crear la lista de usuarios siguiendo la documentación del autor. Fácilmente debes inferir que **repeated** de proto se vuelve vec en Rust.

```proto
message Users {
    repeated UserReply users = 1;
}
```

También debes saber que el crate de Rust Postgresql requiere que incluyas **&[]** (vacío) cuando no hayan valores para pasar en los comandos SQL.

```rs
&conn.query("SELECT * FROM users", &[])
```

**4.** Crearemos un id aleatorio para los usuarios con la API [Rust uuid](https://crates.io/crates/uuid). Debes incluir la **v4** en el archivo `cargo.toml` para que funcione.

```toml
uuid = { version = "0.8.1", features = ["serde", "v4"] }
```

**5.** Usamos la API de [chrono](https://docs.rs/chrono/0.4.9/chrono/) para pasar del tipo `string` a `DATE` y hacerlo compatible con postgresql.

**6.** usamos **let number_of_rows_affected = &conn.execute** y la lógica relevante para manejar el resultado de la base de datos proveniente de la petición hecha al cliente gRPC. Puedes observar que la lógica usada es muy similar in **update_user**, **delete_user** y **delete_users**.

Realmente espero que hayas leido todo el código del proyecto así como la documentación de cada herramienta. Si aún no has probado el proyecto corre el siguiente comando **cargo run --release** y verás algo similar a este mensaje.

```console
Rust gRPC Server ready at [::1]:50051
```

Luego puedes probarlo con **$curl [::1]:50051**.

Si todo funciona bien verás esto.

```console
Warning: Binary output can mess up your terminal. Use "--output -" to tell
Warning: curl to output it to your terminal anyway, or consider "--output
Warning: <FILE>" to save to a file.
```

Luego puedes escribir el código de Tonic del cliente gRPC de la siguiente manera.

```rust
pub mod user {
    tonic::include_proto!("user");
}

use user::{client::CrudClient, UserRequest};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut client = CrudClient::connect("http://[::1]:50051")?;

    let request = tonic::Request::new(UserRequest {
        id: "steadylearner".into(),
    });

    let response = client.get_user(request).await?;

    println!("RESPONSE={:?}", response);
    let user_date_of_birth = &response.into_inner().date_of_birth;
    println!("{}", user_date_of_birth);

    Ok(())
}
```

Será fácil entender como funciona si ya leíste [La guía oficial de Tonic](https://github.com/hyperium/tonic/blob/master/examples/helloworld-tutorial.md). Compilalo si deseas y luego trata de mejorarlo después de que hayas probado todos los endpoints del CRUD con [el cliente gRPC](https://github.com/uw-labs/bloomrpc).

<br />

## 6. Usar el cliente gRPC para probarlo

Para esta parte quiero que ya tengas instalado el [cliente gRPC](https://github.com/uw-labs/bloomrpc) en tu máquina. Deberías tener el archivo ejecutable **BloomRPC version.AppImage** en la carpeta **release**.

Puedes ejecutarlo manualmente, o guiarte para hacerlo con el editor de la siguiente manera.

Usa **pwd** para encontrar la ubicación del cliente gRPC, y **$vim ~/.bashrc** para incluir un alias de esta forma.

```bash
# gRPC

alias grpc-client="grpc/bloomrpc/release/'BloomRPC version.AppImage'"
```

y usa este comando.

```console
$source ~/.bashrc
```

Ahora puedes usarlo con **$grpc-client** cuando lo desees.

Se mostrará la aplicación de escritorio similar la del repositorio oficial.

[![BloomRPC Usage Example from the official repository](https://raw.githubusercontent.com/uw-labs/bloomrpc/master/resources/editor-preview.gif)][gRPC Client]

Si has usado graphql antes, te darás cuenta de que la interfaz es muy similar, así como probar los endpoints con [graphiql](https://github.com/graphql/graphiql).

Primero necesitas incluir los archivo proto que hicimos anteriormente, por ejemplo **user.proto**.

Automáticamente se mostrarán los métodos que puedes usar.

Cada vez que hagas clic en un método, va a mostrarte el valor por defecto en la parte de editor. Puedes enviar peticiones con el valor por defecto o cambiarlo con los valores que quieras.

Para este ejemplo deberías tener cuidado cuando definas el valor de **date_of_birth**. Debes usar el tipo correcto de **DATE** para Rust y Postgresql.

Cuando se pause el proceso, puedes detenerlo fácilmente haciendo clic en el bot´pn que usaste para enviar la petición.

guiate con el siguiente ejemplo.

### GetUser

```json
{
  "id": "steadylearner"
}
```

### ListUsers

```json
{}
```

### CreateUser

```json
{
  "first_name": "steady",
  "last_name": "learner",
  "date_of_birth": "%Y-%m-%d"
}
```

### UpdateUser

```json
{
  "id": "random-id",
  "first_name": "steadylearner",
  "last_name": "rust developer",
  "date_of_birth": "use-numbers-instead"
}
```

### DeleteUser

```json
{
  "id": "steadylearner"
}
```

### DeleteUsers

```json
{}
```

Prueba los endpoints del servidor gRPC con tu propio código.
Luego escribe un cliente Rust [Tonic](https://github.com/hyperium/tonic) más complejo en varios archivos Rust.

[También puedes usar otro servidores Rust para crear microservicios](https://github.com/steadylearner/Rust-Full-Stack/tree/master/microservices_with_docker).

<br />

## 7. Conclusión

Espero que lo hayas logrado hacer funcionar. Te invito a que edites la definición de protobuf para crear tu propio proyecto y crees mas código Rust para manejar la base da datos.

Rust y Tonic me han ayudado a aprender y programar mejor gRPC. Pero, ha sido difícil encontrar ejemplo funcionales con integración de base de datos, y quería que este post fuese de ayuda.

Si deseas seguir mi último contenido, sigueme aquí [Twitter](https://twitter.com/steadylearner_p) o deja una estrella en [Rust Full Stack](https://github.com/steadylearner/Rust-Full-Stack).

[Si necesitas contratar a un desarrollador, puedes contactarme.](https://t.me/steadylearner)

Gracias.