0


Rust使用Actix-web和SeaORM库开发WebAPI通过Swagger UI查看接口文档

本文将介绍Rust语言使用Actix-web和SeaORM库,数据库使用PostgreSQL,开发增删改查项目,同时可以通过Swagger UI查看接口文档和查看标准Rust文档

开始项目

首先创建新项目,名称为rusty_crab_api

cargo new rusty_crab_api

Cargo.toml

[dependencies]
sea-orm = { version = "1.0.0-rc.5", features = [ "sqlx-postgres", "runtime-tokio-native-tls", "macros" ] }
tokio = { version = "1.35.1", features = ["full"] }
chrono = "0.4.33"
actix-web = "4.4.0"
serde = { version = "1.0", features = ["derive"] }
utoipa = { version = "4", features = ["actix_extras"] }
utoipa-swagger-ui = { version = "4", features = ["actix-web"] }
serde_json = "1.0"

使用SeaORM作为ORM工具,它提供了

sea-orm-cli

​工具,方便生成entity

PostgreSQL创建数据库

CREATE TABLE "user" (
  id SERIAL PRIMARY KEY,
  username VARCHAR(32) NOT NULL,
  birthday TIMESTAMP,
  sex VARCHAR(10),
  address VARCHAR(256)
);

COMMENT ON COLUMN "user".username IS '用户名称';
COMMENT ON COLUMN "user".birthday IS '生日';
COMMENT ON COLUMN "user".sex IS '性别';
COMMENT ON COLUMN "user".address IS '地址';

安装

sea-orm-cli

cargo install sea-orm-cli

生成entity

sea-orm-cli generate entity -u postgres://[用户名]:[密码]@[IP]:[PORT]/[数据库] -o src/entity

自动帮我们生成src./entity/user.rs文件

#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]#[sea_orm(table_name = "user")]pubstructModel{#[sea_orm(primary_key)]pub id:i32,pub username:String,pub birthday:Option<DateTime>,pub sex:Option<String>,pub address:Option<String>,}#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]pubenumRelation{}implActiveModelBehaviorforActiveModel{}

接下来编写接口函数,新建src/handlers/user.rs,编写用户表的增删改查代码,同时在代码文件中编写说明文档,提供给Rust标准文档和Swagger UI使用

/// 表示创建新用户的请求体结构#[derive(Debug, Deserialize, ToSchema)]#[schema(example = json!({
    "username": "johndoe",
    "birthday": "2023-09-09T15:53:00",
    "sex": "male",
    "address": "123 Main St, Anytown, USA"
}))]pubstructCreateUser{/// 用户名  pub username:String,/// 生日(可选)#[schema(value_type = String)]pub birthday:Option<DateTime>,/// 性别(可选)pub sex:Option<String>,/// 地址(可选)pub address:Option<String>,}/// 创建新用户////// # 请求体////// 需要一个JSON对象,包含以下字段:/// - `username`: 字符串,用户名(必填)/// - `birthday`: ISO 8601格式的日期时间字符串,用户生日(可选)/// - `sex`: 字符串,用户性别(可选)/// - `address`: 字符串,用户地址(可选)////// # 响应////// - 成功:返回状态码200和新创建的用户JSON对象/// - 失败:返回状态码500////// # 示例////// ‍‍```/// POST /users/// Content-Type: application/json////// {///     "username": "johndoe",///     "birthday": "1990-01-01T00:00:00",///     "sex": "M",///     "address": "123 Main St, Anytown, USA"/// }/// ‍‍```#[utoipa::path(
    post,
    path = "/api/users",
    request_body = CreateUser,
    responses(
        (status = 200, description = "User created successfully", body = Model),
        (status = 500, description = "Internal server error")
    )
)]pubasyncfncreate_user(
    db:web::Data<sea_orm::DatabaseConnection>,
    user_data:web::Json<CreateUser>,)->implResponder{let user =UserActiveModel{
        username:Set(user_data.username.clone()),
        birthday:Set(user_data.birthday),
        sex:Set(user_data.sex.clone()),
        address:Set(user_data.address.clone()),..Default::default()};let result = user.insert(db.get_ref()).await;match result {Ok(user)=>HttpResponse::Ok().json(user),Err(_)=>HttpResponse::InternalServerError().finish(),}}/// 获取指定ID的用户信息////// # 路径参数////// - `id`: 整数,用户ID////// # 响应////// - 成功:返回状态码200和用户JSON对象/// - 未找到:返回状态码404/// - 失败:返回状态码500////// # 示例////// ‍‍```/// GET /users/1/// ‍‍```#[utoipa::path(
    get,
    path = "/api/users/{id}",
    responses(
        (status = 200, description = "User found", body = Model),
        (status = 404, description = "User not found"),
        (status = 500, description = "Internal server error")
    ),
    params(
        ("id" = i32, Path, description = "User ID")
    )
)]pubasyncfnget_user(
    db:web::Data<sea_orm::DatabaseConnection>,
    id:web::Path<i32>,)->implResponder{let user =user::Entity::find_by_id(*id).one(db.get_ref()).await;println!("{id}");match user {Ok(Some(user))=>HttpResponse::Ok().json(user),Ok(None)=>HttpResponse::NotFound().finish(),Err(_)=>HttpResponse::InternalServerError().finish(),}}/// 更新指定ID的用户信息////// # 路径参数////// - `id`: 整数,用户ID////// # 请求体////// 需要一个JSON对象,包含以下字段(所有字段都是可选的):/// - `username`: 字符串,新的用户名/// - `birthday`: ISO 8601格式的日期时间字符串,新的用户生日/// - `sex`: 字符串,新的用户性别/// - `address`: 字符串,新的用户地址////// # 响应////// - 成功:返回状态码200和更新后的用户JSON对象/// - 未找到:返回状态码404/// - 失败:返回状态码500////// # 示例////// ‍‍```/// PUT /users/1/// Content-Type: application/json////// {///     "username": "johndoe_updated",///     "address": "456 Elm St, Newtown, USA"/// }/// ‍‍```#[utoipa::path(
    put,
    path = "/api/users/{id}",
    request_body = CreateUser,
    responses(
        (status = 200, description = "User updated successfully", body = Model),
        (status = 404, description = "User not found"),
        (status = 500, description = "Internal server error")
    ),
    params(
        ("id" = i32, Path, description = "User ID")
    )
)]pubasyncfnupdate_user(
    db:web::Data<sea_orm::DatabaseConnection>,
    id:web::Path<i32>,
    user_data:web::Json<CreateUser>,)->implResponder{let user =user::Entity::find_by_id(*id).one(db.get_ref()).await;match user {Ok(Some(user))=>{letmut user:UserActiveModel= user.into();
            user.username =Set(user_data.username.clone());
            user.birthday =Set(user_data.birthday);
            user.sex =Set(user_data.sex.clone());
            user.address =Set(user_data.address.clone());let result = user.update(db.get_ref()).await;match result {Ok(updated_user)=>HttpResponse::Ok().json(updated_user),Err(_)=>HttpResponse::InternalServerError().finish(),}}Ok(None)=>HttpResponse::NotFound().finish(),Err(_)=>HttpResponse::InternalServerError().finish(),}}/// 删除指定ID的用户////// # 路径参数////// - `id`: 整数,用户ID////// # 响应////// - 成功:返回状态码204(无内容)/// - 失败:返回状态码500////// # 示例////// ‍‍```/// DELETE /users/1/// ‍‍```#[utoipa::path(
    delete,
    path = "/api/users/{id}",
    responses(
        (status = 204, description = "User deleted successfully"),
        (status = 500, description = "Internal server error")
    ),
    params(
        ("id" = i32, Path, description = "User ID")
    )
)]pubasyncfndelete_user(
    db:web::Data<sea_orm::DatabaseConnection>,
    id:web::Path<i32>,)->implResponder{let result =user::Entity::delete_by_id(*id).exec(db.get_ref()).await;match result {Ok(_)=>HttpResponse::NoContent().finish(),Err(_)=>HttpResponse::InternalServerError().finish(),}}

为了使用Swagger UI查看接口文档,还需要创建src/api_doc.rs文件

#[derive(OpenApi)]#[openapi(
    paths(
        handlers::user::create_user,
        handlers::user::get_user,
        handlers::user::update_user,
        handlers::user::delete_user
    ),
    components(
        schemas(Model,CreateUser)
    ),
    tags(
        (name = "users", description = "User management API")
    )
)]pubstructApiDoc;

在src/main.rs文件定义路由和配置Swagger UI

#[actix_web::main]asyncfnmain()->std::io::Result<()>{let db:DatabaseConnection=db::establish_connection().await;let db_data =web::Data::new(db);HttpServer::new(move||{App::new().app_data(db_data.clone()).service(web::scope("/api").service(web::scope("/users").route("",web::post().to(create_user)).route("/{id}",web::get().to(get_user)).route("/{id}",web::put().to(update_user)).route("/{id}",web::delete().to(delete_user)).route("/test",web::get().to(||async{"Hello, World!"})))).service(SwaggerUi::new("/swagger-ui/{_:.*}").url("/api-docs/openapi.json",ApiDoc::openapi()))}).bind("127.0.0.1:8080")?.run().await}

到这里,项目完成开发,启动项目

cargo run

查看Swagger UI接口文档

浏览器打开

http://localhost:8080/swagger-ui/

在这里插入图片描述

在这里插入图片描述

可以看到我们在Rust代码文件中的注释说明,这对于接口使用人员和代码维护人员都非常友好,当然对于接口的简单测试,在这个页面也是非常方便去进行

查看Rust标准文档

cargo doc --open

在这里插入图片描述

在这里插入图片描述

最后

项目的完整代码可以查看我的仓库​:https://github.com/VinciYan/rusty_crab_api.git

后续,我还会介绍如何使用Rust语言Web开发框架Salvo和SeaORM结合开发WebAPI

标签: rust web orm

本文转载自: https://blog.csdn.net/mengningyun6826/article/details/142220255
版权归原作者 VinciYan 所有, 如有侵权,请联系我们删除。

“Rust使用Actix-web和SeaORM库开发WebAPI通过Swagger UI查看接口文档”的评论:

还没有评论