所有文章 > 如何集成API > 使用 Rust 构建功能完整的 gRPC API
使用 Rust 构建功能完整的 gRPC API

使用 Rust 构建功能完整的 gRPC API

本文将展示如何使用 Rust 构建一个完整的 gRPC API。通过本教程,你将学习如何:

  • 定义服务协议(Protobuf)
  • 编译 Protobuf 文件生成 Rust 代码
  • 实现 gRPC 服务器和客户端
  • 测试和验证服务

一. 先决条件

在开始之前,请确保你已安装以下工具:

  • Rust 编译器及工具链(最新稳定版)
  • Protobuf 编译器(protoc
  • cargo 包管理器
  • 基本 Rust 编程知识

二. 创建项目脚手架

选择一个工作目录,并使用 cargo 创建 Rust 项目:

cargo new demo
cd demo

此时项目目录结构已经就绪,可用于后续开发。


三. 定义服务协议(Protobuf)

我们将创建一个 杂货店库存服务,支持:

  • 查看、添加商品
  • 更新库存数量和价格
  • 观察库存变化(流式调用)
  1. 创建 proto/ 目录:
mkdir proto
  1. proto/ 下创建 store.proto 文件:
syntax = "proto3";

package store;

service Inventory {
  rpc Add(Item) returns (Response);
  rpc Remove(ItemId) returns (Response);
  rpc Get(ItemId) returns (Item);
  rpc UpdateQuantity(UpdateRequest) returns (Response);
  rpc UpdatePrice(UpdateRequest) returns (Response);
  rpc Watch(WatchRequest) returns (stream Item);
}

message Item {
  string id = 1;
  string name = 2;
  int32 quantity = 3;
  float price = 4;
}

message ItemId {
  string id = 1;
}

message UpdateRequest {
  string id = 1;
  int32 quantity = 2;
  float price = 3;
}

message Response {
  string message = 1;
}

message WatchRequest {
  string filter = 1;
}

四. 编译 Protobuf 文件

Cargo.toml 添加依赖:

[dependencies]
tonic = "0.7"
prost = "0.11"

[build-dependencies]
tonic-build = "0.7"

创建 build.rs 文件,用于在构建时自动生成 Rust 代码:

fn main() {
    tonic_build::configure()
        .build_server(true)
        .build_client(true)
        .out_dir("src/")
        .compile(&["proto/store.proto"], &["proto"])
        .unwrap();
}

生成代码:

cargo build

生成的 src/store.rs 包含客户端和服务器代码。


五. 实现服务器

  1. 创建 src/server.rs
use tonic::{transport::Server, Request, Response, Status};
use std::sync::{Arc, Mutex};
use std::collections::HashMap;

mod store {
    tonic::include_proto!("store");
}

use store::inventory_server::{Inventory, InventoryServer};
use store::{Item, ItemId, Response as StoreResponse, UpdateRequest};
  1. 定义库存管理结构:
#[derive(Default)]
pub struct StoreInventory {
    inventory: Arc<Mutex<HashMap<String, Item>>>,
}
  1. 实现 Inventory 服务方法:

添加商品

#[tonic::async_trait]
impl Inventory for StoreInventory {
    async fn add(&self, request: Request<Item>) -> Result<Response<StoreResponse>, Status> {
        let item = request.into_inner();
        let mut inventory = self.inventory.lock().unwrap();

        if inventory.contains_key(&item.id) {
            return Err(Status::already_exists("Item already exists"));
        }

        inventory.insert(item.id.clone(), item);
        Ok(Response::new(StoreResponse {
            message: "Item added successfully".to_string(),
        }))
    }
}

删除商品

async fn remove(&self, request: Request<ItemId>) -> Result<Response<StoreResponse>, Status> {
    let id = request.into_inner().id;
    let mut inventory = self.inventory.lock().unwrap();

    if inventory.remove(&id).is_some() {
        Ok(Response::new(StoreResponse {
            message: "Item removed successfully".to_string(),
        }))
    } else {
        Err(Status::not_found("Item not found"))
    }
}

更新库存数量

async fn update_quantity(&self, request: Request<UpdateRequest>) -> Result<Response<StoreResponse>, Status> {
    let update = request.into_inner();
    let mut inventory = self.inventory.lock().unwrap();

    if let Some(item) = inventory.get_mut(&update.id) {
        item.quantity += update.quantity;
        Ok(Response::new(StoreResponse {
            message: "Quantity updated successfully".to_string(),
        }))
    } else {
        Err(Status::not_found("Item not found"))
    }
}
  1. 启动服务器:
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let addr = "[::1]:50051".parse()?;
    let inventory = StoreInventory::default();

    Server::builder()
        .add_service(InventoryServer::new(inventory))
        .serve(addr)
        .await?;

    Ok(())
}

六. 实现客户端

  1. 创建客户端逻辑,例如添加商品:
async fn add_item(client: &mut store::inventory_client::InventoryClient<tonic::transport::Channel>,
                  id: &str, name: &str, quantity: i32, price: f32) {
    let item = Item {
        id: id.to_string(),
        name: name.to_string(),
        quantity,
        price,
    };

    let response = client.add(Request::new(item)).await.unwrap();
    println!("Response: {}", response.into_inner().message);
}
  1. 启动客户端:
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut client = store::inventory_client::InventoryClient::connect("http://[::1]:50051").await?;

    add_item(&mut client, "1", "Apple", 100, 1.5).await;

    Ok(())
}

七. 测试服务

运行服务器和客户端:

cargo run --bin server
cargo run --bin client

测试添加、删除、更新商品,观察服务器响应。


八. 总结

通过本教程,你已经学会:

  • 使用 Rust 定义 gRPC 服务协议(Protobuf)
  • 编译 Protobuf 文件生成 Rust 代码
  • 实现 gRPC 服务器和客户端
  • 测试完整的 gRPC API

下一步,你可以尝试添加 TLS 加密身份验证流式订阅功能,提升服务安全性和功能丰富度。

原文链接:Kong Engineering Blog

#你可能也喜欢这些API文章!

我们有何不同?

API服务商零注册

多API并行试用

数据驱动选型,提升决策效率

查看全部API→
🔥

热门场景实测,选对API

#AI文本生成大模型API

对比大模型API的内容创意新颖性、情感共鸣力、商业转化潜力

25个渠道
一键对比试用API 限时免费

#AI深度推理大模型API

对比大模型API的逻辑推理准确性、分析深度、可视化建议合理性

10个渠道
一键对比试用API 限时免费