Как использовать gRPC с Rust Tonic и Postgres с примерами

В этом посте мы узнаем, как использовать Rust, Tonic и gRPC crate, и реализуем CRUD с базой данных Postgresql.

Вы можете связаться со мной по Telegram, если вам нужно нанять Full Stack Blockchain разработчика.

Вы также можете присоединиться к моей группе в Telegram, где вы можете найти других разработчиков blockchain, а также рекрутеров, менеджеров проектов, а также задать вопросы и наладить связи.

Цель этой заметки – помочь вам работать с Rust Tonic, чтобы вы могли начать программировать свой собственный проект.

Пререквизиты

  1. Что такое gRPC и буферы протоколов?
  2. Rust, Postgresql (или другие базы данных)
  3. Официальный гид по тоникам
  4. клиент gRPC

Если на вашем компьютере не установлен Rust, прочитайте статью Как установить Rust. В этом посте мы будем использовать Rust Postgresql crate. Вам следует установить Postgresql, если вы этого еще не сделали.

Я предположу, что вы уже знакомы с gRPC, Rust и базой данных Postgresql. В противном случае, пожалуйста, прочитайте документацию перед началом работы.

Вам может не понадобиться клиент gRPC. Но я оставлю его здесь перед остальным контентом, потому что он очень полезен и занимает много времени на установку. Чтобы сэкономить ваше время, я оставлю инструкцию.

Оглавление.

  1. Настройка проекта
  2. Определите службу gRPC для CRUD
  3. Подготовка нашего Cargo.toml к установке зависимостей
  4. Создайте сервер gRPC с помощью Tonic
  5. Реализуйте службу gRPC для CRUD с помощью Rust Postgresql
  6. Использование клиента gRPC для тестирования
  7. Заключение

Я повторно использовал некоторые части официального руководства Tonic, чтобы поток работал аналогичным образом. Это поможет вам лучше понять суть сообщения.

Вы можете найти исходный код здесь

1. конфигурация проекта

Первое, что мы сделаем, это установим данные для базы данных. Надеюсь, у вас на компьютере уже установлена какая-нибудь база данных SQL. Вы можете обратиться к этим командам SQL.

Вы можете называть свою базу данных как угодно.

CREATE DATABASE grpc OWNER you;
c grpc;
Войдите в полноэкранный режим Выход из полноэкранного режима

Затем введите, $psql users < users.sql или вставьте их вручную в консоль psql после аутентификации.

-- 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');
Войдите в полноэкранный режим Выход из полноэкранного режима

Затем вы можете сохранить эти данные из Postgresql с помощью $pg_dump users > users.sql.

Конфигурация базы данных готова. Теперь создайте новый проект Rust, чтобы использовать его и научиться использовать Tonic.

$cargo new user
$cd user
Войдите в полноэкранный режим Выход из полноэкранного режима

Создайте файл .env в папке для защиты вашей базы данных и информации для входа, используйте эту команду в качестве руководства.

$echo DATABASE_URL=postgres://postgres:postgres@localhost/grpc > .env
Войдите в полноэкранный режим Выход из полноэкранного режима

2. Определите службу gRPC для CRUD

В последнем разделе мы подготовили минимальную конфигурацию для этого поста. Теперь мы определим службу gRPC с методом запроса и ответа. Мы будем использовать буферы протокола для использования данных, которые мы сделали с помощью Postgresql.

Мы создадим файлы .proto в папке proto. Используйте эти команды.

$mkdir proto
$touch proto/user.proto
Войдите в полноэкранный режим Выход из полноэкранного режима

Сначала мы определим имя нашего пакета – это имя, которое Tonic использует, включая протосы в клиентском и серверном приложениях. В данном случае это будет пользователь.

syntax = "proto3";
package user;
Войдите в полноэкранный режим Выход из полноэкранного режима

Теперь мы определим наш CRUD-сервис. Эта служба будет содержать фактические вызовы gRPC. Мы будем использовать их для создания примера Rust with Tonic CRUD.

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) {}
}
Войдите в полноэкранный режим Выход из полноэкранного режима

На данный момент ничего сложного. Я знаю, что это немного многословно, но это сделано для того, чтобы сделать логику более явной и легкой для разделения.

Если у вас есть лучший способ сделать это или у вас больше опыта работы с gRPC, не стесняйтесь связаться со мной в Twitter или вы также можете создать проблему на Github.

Наконец, мы укажем типы, которые мы используем в методе RPC нашего CRUD. Типы RPC определяются как сообщения, содержащие поля по типу. Что-то похожее на это.

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;
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Вы можете видеть, что я использовал тип string для date_of_birth вместо date. Я сделал это, потому что не мог найти подходящий пример для типа DATE в protobuf и заставить его работать с Tonic, Protocol Buffers и системой типов Rust.

Если вы разбираетесь в этом или имеете больше опыта, чтобы сделать это лучше, я буду благодарен, если вы поможете мне исправить это.

После завершения наш .proto файл нашего CRUD должен выглядеть примерно так.

// 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;
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Я обнаружил, что работать с Rust непросто, и становится все труднее компилировать его без ошибок, когда мы хотим одновременно задать типы данных буфера протокола и Rust Postgresql.

Если вы хотите сделать свой собственный Rust Tonic проект с другими proto файлами, сначала скомпилируйте Tonic CRUD Example by Steadylearner, чтобы собрать бинарные файлы и начать редактировать Rust код и protbuf определения там небольшими частями.

3. Подготовка нашего Cargo.toml к установке зависимостей

Мы настроили проект и создали файл protobuf для использования gRPC с Rust. Итак, теперь мы можем писать код для Rust с помощью Tonic.

Первое, что нужно сделать, это подготовить зависимости с помощью Cargo.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"
Войдите в полноэкранный режим Выход из полноэкранного режима

Для этого простого проекта существует множество зависимостей.
Но если вы посмотрите на эту часть, вам будет легче понять.

# 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"] }
Войдите в полноэкранный режим Выход из полноэкранного режима

Этот блок предназначен для Rust Postgresql, а остальные – для Tonic.

Мы включаем tonic-build для создания нашего клиентского и серверного gRPC-кода.

Если вы не использовали gRPC или Tonic, вы можете быть в замешательстве.
Но все языки, использующие gRPC, имеют схожий процесс использования определений буферов proto с ними.

С Rust Tonic мы должны включить его в процесс build нашего приложения. Мы настроим его с помощью build.rs в корне crate.

fn main() -> Result<(), Box<dyn std::error::Error>> {
    tonic_build::compile_protos("proto/user.proto")?;
    Ok(())
}
Войдите в полноэкранный режим Выход из полноэкранного режима

На данный момент нет ничего сложного, вам просто нужно изменить имя файла других примеров. Таким образом, tonic-build скомпилирует файлы protobufs для работы с проектами Rust, в которых интегрирован gRPC.

Он автоматически создаст некоторые модули Rust для последующего использования в вашем коде Rust в зависимости от определений protobuf, которые вы использовали в файлах protobuf. Вы можете убедиться в этом с помощью кода Rust, о котором вы прочитаете в ближайшее время.

Более подробную информацию можно найти в разделе tonic-build.

4. Создание сервера gRPC с помощью Tonic

Процесс подготовки завершился в последней части.
Наконец, мы напишем наш Rust-код, начиная создавать Rust Tonic gRPC-сервер, следующим образом.

// 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(())
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Это будет точка входа, когда мы запустим наш сервер. В основном это определение зависимостей и модулей, которые мы будем использовать.

Файл прост, но в нем есть несколько моментов, которые необходимо понять.

1. Здесь мы можем использовать автоматически сгенерированный код из tonic_build::compile_protos(“proto/user.proto”)?; и tonic-build = “0.1.0-alpha.4”.

Вы можете использовать модули, созданные аналогично этому, а также обработчики, которые мы создадим в models.rs.

use user::{
    server::{CrudServer},
};
Войдите в полноэкранный режим Выход из полноэкранного режима

2. Содержимое файла db_connection должно выглядеть следующим образом.

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()
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Его можно использовать повторно без изменений, мы выделим его в функцию и будем вызывать ее, откуда захотим.

3. Это код от создателей Tonic. Вы должны использовать его без префикса HTTP при использовании CURL и клиента gRPC.

4. Мы используем console::Style; с println!, чтобы легко посещать сервер с помощью браузеров и иметь возможность отправлять CURL-команды.

5. Реализация службы CRUD gRPC с помощью Rust Postgresql

В этой части мы создадим несколько обработчиков в файле service.rs, следуя определениям, которые мы сделали в файле user.proto. Остальная часть кода будет похожа на это.

Следующий блок – длинный блок. Этот блок предназначен для реализации всех операций gRPC CRUD с базой данных Postgresql. Прочитайте те части, которые вас заинтересовали.

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))
    }
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Как вы можете видеть, здесь много строк кода, поэтому для начала будет немного сложно. Я хочу, чтобы вы протестировали этот проект с частями get_user и list_users. Таким образом, вы сможете улучшить его и проконсультироваться с ним, добавив комментарии.

1. Когда мы читаем документацию по Rust Postgresql, мы понимаем, что в нем есть команды execute и query. Разница в том, что execute возвращает количество измененных строк, а query возвращает данные. Вы должны быть в состоянии найти, какой из них использовать в зависимости от ваших потребностей.

2. При использовании Rust Postgresql вы можете получить ошибку, подобную этой.

cannot infer type
the trait `postgres::types::FromSql` is not implemented for
Войдите в полноэкранный режим Выход из полноэкранного режима

Если да, то вам следует изменить тип определения данных, чтобы помочь Rust поддерживать postgresql с chrono.

let date_of_birth: NaiveDate = row.get(3);
Войдите в полноэкранный режим Выход из полноэкранного режима

Мы используем строковый тип данных для date_of_birth в файле user.proto. Мы должны изменить его следующим образом.

date_of_birth: date_of_birth.to_string(),
Войдите в полноэкранный режим Выход из полноэкранного режима

Это цена, которую мы должны заплатить за то, чтобы Rust работал в связке с Postgresql и Protobuf. Возможно, вы придумаете лучший способ сделать это.

3. Мы используем императивную форму для создания списка пользователей, следуя авторской документации. Вы должны легко понять, что повторение proto становится vec в Rust.

message Users {
    repeated UserReply users = 1;
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Вы также должны знать, что Rust Postgresql crate требует включать &[] (пусто), когда в SQL-командах нет значений для передачи.

&conn.query("SELECT * FROM users", &[])
Войдите в полноэкранный режим Выход из полноэкранного режима

4. Мы создадим случайный идентификатор для пользователей с помощью API Rust uuid. Вы должны включить v4 в файл cargo.toml, чтобы это работало.

uuid = { version = "0.8.1", features = ["serde", "v4"] }
Войдите в полноэкранный режим Выход из полноэкранного режима

5. Используйте chrono API для изменения типа string на DATE и сделайте его совместимым с postgresql.

6. мы используем let number_of_rows_affected = &conn.execute и соответствующую логику для обработки результата базы данных от запроса, сделанного клиенту gRPC. Вы можете видеть, что используемая логика очень похожа в update_user, delete_user и delete_users.

Я очень надеюсь, что вы прочитали весь код в проекте, а также документацию по каждому инструменту. Если вы еще не тестировали проект, выполните следующую команду cargo run –release и вы увидите что-то похожее на это сообщение.

Rust gRPC Server ready at [::1]:50051
Войдите в полноэкранный режим Выход из полноэкранного режима

Затем вы можете проверить его с помощью $curl [::1]:50051.

Если все работает нормально, вы увидите следующее.

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.
Войдите в полноэкранный режим Выход из полноэкранного режима

Затем вы можете написать код Tonic для клиента gRPC следующим образом.

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(())
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Вам будет легко понять, как это работает, если вы уже читали официальное руководство по Tonic. Скомпилируйте его, если хотите, а затем попробуйте улучшить его после того, как протестируете все конечные точки CRUD с помощью клиента gRPC.

6. Использование клиента gRPC для тестирования

Для этой части я хочу, чтобы на вашей машине уже был установлен клиент gRPC. У вас должен быть исполняемый файл BloomRPC version.AppImage в папке release.

Вы можете запустить его вручную или сделать это с помощью редактора следующим образом.

Используйте pwd, чтобы найти местоположение клиента gRPC, и $vim ~/.bashrc, чтобы включить псевдоним, например, такой.

# gRPC

alias grpc-client="grpc/bloomrpc/release/'BloomRPC version.AppImage'"
Войдите в полноэкранный режим Выход из полноэкранного режима

и используйте эту команду.

$source ~/.bashrc
Войдите в полноэкранный режим Выход из полноэкранного режима

Теперь вы можете использовать его с $grpc-client, когда захотите.

Он отобразит настольное приложение, аналогичное тому, что находится в официальном репозитории.

Если вы уже использовали graphql, вы заметите, что интерфейс очень похож, также как и тестирование конечных точек с помощью graphiql.

Сначала необходимо включить файлы proto, которые мы создали ранее, например user.proto.

Он автоматически покажет методы, которые вы можете использовать.

Каждый раз, когда вы нажимаете на метод, он будет показывать вам значение по умолчанию в части редактора. Вы можете отправлять запросы со значением по умолчанию или изменить его на любое нужное вам значение.

В данном примере следует быть осторожным при определении значения date_of_birth. Вы должны использовать правильный тип DATE для Rust и Postgresql.

Когда процесс приостановлен, вы можете легко остановить его, нажав на bot’pn, который вы использовали для отправки запроса.

Используйте следующий пример в качестве руководства.

GetUser

{
  "id": "steadylearner"
}
Войдите в полноэкранный режим Выход из полноэкранного режима

ListUsers

{}
Войдите в полноэкранный режим Выход из полноэкранного режима

CreateUser

{
  "first_name": "steady",
  "last_name": "learner",
  "date_of_birth": "%Y-%m-%d"
}
Войдите в полноэкранный режим Выход из полноэкранного режима

UpdateUser

{
  "id": "random-id",
  "first_name": "steadylearner",
  "last_name": "rust developer",
  "date_of_birth": "use-numbers-instead"
}
Войдите в полноэкранный режим Выход из полноэкранного режима

DeleteUser

{
  "id": "steadylearner"
}
Войдите в полноэкранный режим Выход из полноэкранного режима

DeleteUsers

{}
Войдите в полноэкранный режим Выход из полноэкранного режима

Протестируйте конечные точки сервера gRPC с помощью собственного кода.
Затем напишите более сложный клиент Rust Tonic в нескольких файлах Rust.

Вы также можете использовать другие серверы Rust для создания микросервисов.

7. Заключение

Надеюсь, вам удалось заставить его работать. Я предлагаю вам отредактировать определение protobuf, чтобы создать свой собственный проект и создать больше кода Rust для работы с базой данных.

Rust и Tonic помогли мне лучше изучить и запрограммировать gRPC. Но было трудно найти функциональные примеры с интеграцией баз данных, и я хотел, чтобы этот пост помог вам.

Если вы хотите следить за моими последними материалами, следите за мной в Twitter или оставьте звезду на Rust Full Stack.

Если вам нужно нанять разработчика, не стесняйтесь обращаться ко мне.

Спасибо.

Оцените статью
Procodings.ru
Добавить комментарий