使用Rust构建API

Rust,API

 0
使用Rust构建API

一般在自己个人项目中我喜欢使用 Rust。用独特的方式结合了速度、安全性和并发性开发强大的API。
可以使用MongoDB或PostgreSQL数据库创建一个CRUDAPI,在这里我使用MySQL数据库来构建相同的功能。
首先设置DOCKER,MySQL后使用SQLx-CLI进行架构迁移,最后创建CRUDAPI控制器,并在服务器上配置CORS允许跨源请求。


设置 Rust API
先设置Rust项目:

创建文件夹:

创建一个名为rust-mysql-api

初始化项目:
在终端中新创建的文件夹并运行命令cargo init初始化Rust二进制项目。

在VSCODE中打开项目:
初始化项目后,在编辑器或集成开发环境中打开文件夹。

安装所需的包:
在代码编辑器中打开集成终端并运行以下命令来安装所有的依赖项。

cargo add axum
cargo add tokio -F full
cargo add tower-http -F "cors"
cargo add serde_json
cargo add serde -F derive
cargo add chrono -F serde
cargo add dotenv
cargo add uuid -F "serde v4"
cargo add sqlx -F "runtime-async-std-native-tls mysql chrono uuid"

Cargo.toml

[package]
name = "rust-l-crud-api"
version = "0.1.0"
edition = "2021"

[dependencies]
axum = "0.7.7"
chrono = { version = "0.4.38", features = ["serde"] }
dotenv = "0.15.0"
serde = { version = "1.0.210", features = ["derive"] }
serde_json = "1.0.128"
sqlx = { version = "0.8.2", features = ["runtime-native-tls", "mysql", "chrono", "uuid"] }
tokio = { version = "1.40.0", features = ["full"] }
tower-http = { version = "0.6.1", features = ["cors"] }
uuid = { version = "1.10.0", features = ["serde", "v4"] }
  • chrono– Rust 的日期和时间库
  • dotenv– 从文件加载环境变量.env
  • serde– 用于序列化和反序列化 Rust 数据结构的框架
  • sqlx– Rust 的 SQL 工具包
  • tokio– 使用 Rust 编写异步应用程序的运行时
  • tower-http– 拥有大量在构建 HTTP 服务器和客户端时非常有用的中间件

在Docker启动MySQL服务器实例,在根目录中创建一个docker-compose.yml文件添加Docker配置:

docker-compose.yml

services:
  mysql:
    image: mysql:latest
    container_name: mysql
    env_file:
      - ./.env
    ports:
      - '6500:3306'
    volumes:
      - mysqlDB:/var/lib/mysql
  phpMyAdmin:
    image: phpmyadmin
    restart: always
    container_name: phpMyAdmin
    env_file:
      - ./.env
    environment:
      - PMA_HOST=mysql
    ports:
      - '8080:80'
    depends_on:
      - mysql
volumes:
  mysqlDB:

.env

MYSQL_DATABASE=rust_sqlx
MYSQL_USER=admin
MYSQL_PASSWORD=password123
MYSQL_ROOT_PASSWORD=password123


DATABASE_URL=mysql://${MYSQL_USER}:${MYSQL_PASSWORD}@localhost:6500/${MYSQL_DATABASE}

使用 SQLx 执行数据库迁移

现在 MySQL 数据库已启动并运行,创建必要的表,使用 SQLx-CLI 工具包通过代码完全处理此问题。确保已安装 SQLx-CLI。

可以通过运行以下命令来安装:cargo install sqlx-cli

安装 SQLx-CLI 后,运行命令在sqlx migrate add -r init内生成“up”和“down”迁移脚本migrations

打开“up”迁移脚本并包含以下 SQL 语句feedbacks在数据库中创建表:

CREATE TABLE feedbacks (
    id CHAR(36) PRIMARY KEY NOT NULL,
    name VARCHAR(255) NOT NULL,
    email VARCHAR(255) NOT NULL,
    feedback VARCHAR(500) NOT NULL UNIQUE,
    rating FLOAT CHECK (rating >= 1 AND rating <= 5) NOT NULL,
    status VARCHAR(50) DEFAULT 'pending',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

创建数据库模型

use serde::{Deserialize, Serialize};
use sqlx::FromRow;

#[derive(Debug, Serialize, Deserialize, FromRow)]
pub struct Feedback {
    pub id: String,
    pub name: String,
    pub email: String,
    pub feedback: String,
    pub rating: i32,
    pub status: Option,
  
    pub created_at: Option>,
 
    pub updated_at: Option>,
}

schema.rs

use serde::{Deserialize, Serialize};


pub struct FilterOptions {
    pub page: Option,
    pub limit: Option,
}


pub struct CreateFeedbackSchema {
    pub name: String,
    pub email: String,
    pub feedback: String,
    pub rating: i32,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub status: Option,
}


pub struct UpdateFeedbackSchema {
    pub name: Option,
    pub email: Option,
    pub feedback: Option,
    pub rating: Option,
    pub status: Option,
}

API 路由

use std::sync::Arc;

use axum::{
    routing::{get, post},
    Router,
};

use crate::{
    handlers::{
        create_feedback_handler, delete_feedback_handler, edit_feedback_handler, get_feedback_handler,
        health_checker_handler, feedback_list_handler,
    },
    AppState,
};

pub fn create_router(app_state: Arc) -> Router {
    Router::new()
        .route("/api/healthchecker", get(health_checker_handler))
        .route("/api/feedbacks/", post(create_feedback_handler))
        .route("/api/feedbacks", get(feedback_list_handler))
        .route(
            "/api/feedbacks/:id",
            get(get_feedback_handler)
                .patch(edit_feedback_handler)
                .delete(delete_feedback_handler),
        )
        .with_state(app_state)
}

你的反应是什么?

like

dislike

love

funny

angry

sad

wow