ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

rust actix-web swagger如何编写

2026/9/28 21:26:47 拓冰建站 浏览量
rust actix-web swagger如何编写 # Rust Actix-Web 集成 Swagger (OpenAPI)在 Rust Actix-Web 生态中,最常用的方案是 **utoipa** **utoipa-swagger-ui**(utoipa v5.x 之后,actix-web 集成从 utoipa-swagger-ui 独立到 utoipa-actix-web)。## 一、依赖配置### 方案 A:utoipa v4.x(推荐入门,生态稳定)toml[dependencies]actix-web 4serde { version 1, features [derive] }serde_json 1utoipa { version 4, features [actix_extras] }utoipa-swagger-ui { version 6, features [actix-web] }### 方案 B:utoipa v5.x(较新)toml[dependencies]actix-web 4serde { version 1, features [derive] }utoipa { version 5, features [actix_extras] }utoipa-actix-web 0.1utoipa-swagger-ui { version 8, features [actix-web] }下面以 **v4 方案** 为例,兼容性最好。---## 二、完整示例代码rustuse actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder};use serde::{Deserialize, Serialize};use utoipa::{OpenApi, ToSchema};use utoipa_swagger_ui::SwaggerUi;// 数据模型 #[derive(Serialize, Deserialize, ToSchema)]struct User {id: i64,name: String,email: String,}#[derive(Serialize, Deserialize, ToSchema)]struct CreateUser {name: String,email: String,}#[derive(Serialize, ToSchema)]struct ErrorResponse {code: i32,message: String,}// 请求处理器 /// 获取用户列表#[utoipa::path(get,path /users,tag user,responses((status 200, description 查询成功, body VecUser),))]#[get(/users)]async fn list_users() - impl Responder {let users vec![User { id: 1, name: Alice.into(), email: aliceexample.com.into() },User { id: 2, name: Bob.into(), email: bobexample.com.into() },];HttpResponse::Ok().json(users)}/// 根据 ID 获取用户#[utoipa::path(get,path /users/{id},tag user,params((id i64, Path, description 用户 ID)),responses((status 200, description 查询成功, body User),(status 404, description 用户不存在, body ErrorResponse),))]#[get(/users/{id})]async fn get_user(path: web::Pathi64) - impl Responder {let id path.into_inner();if id 1 {HttpResponse::Ok().json(User {id,name: Alice.into(),email: aliceexample.com.into(),})} else {HttpResponse::NotFound().json(ErrorResponse {code: 404,message: not found.into(),})}}/// 创建用户#[utoipa::path(post,path /users,tag user,request_body CreateUser,responses((status 200, description 创建成功, body User),(status 400, description 参数错误, body ErrorResponse),))]#[post(/users)]async fn create_user(body: web::JsonCreateUser) - impl Responder {let user User {id: 100,name: body.name.clone(),email: body.email.clone(),};HttpResponse::Ok().json(user)}// OpenApi 文档定义 #[derive(OpenApi)]#[openapi(paths(list_users, get_user, create_user),components(schemas(User, CreateUser, ErrorResponse)),tags((name user, description 用户管理 API)),info(title Demo API,version 1.0.0,description Actix-Web Utoipa 示例))]struct ApiDoc;// main #[actix_web::main]async fn main() - std::io::Result() {println!(Swagger UI: http://127.0.0.1:8080/swagger-ui/);HttpServer::new(|| {App::new().service(SwaggerUi::new(/swagger-ui/{_:.*}).url(/api-docs/openapi.json, ApiDoc::openapi()),).service(list_users).service(get_user).service(create_user)}).bind((127.0.0.1, 8080))?.run().await}运行后访问:- Swagger UI: http://127.0.0.1:8080/swagger-ui/- OpenAPI JSON: http://127.0.0.1:8080/api-docs/openapi.json---## 三、关键点详解### 1. #[utoipa::path] 宏标注在 handler 函数上,描述该接口:| 参数 | 说明 ||------|------|| get/post/put/delete | HTTP 方法 || path /xxx | 路由路径,**必须与 #[get(...)] 一致** || tag | 分组标签,便于 UI 分类 || params(...) | 路径/查询/Header 参数 || request_body T | 请求体类型 || responses(...) | 响应定义 |### 2. 参数写法rustparams(// 路径参数(id i64, Path, description 用户 ID),// 查询参数(page Optionu32, Query, description 页码),// Header(X-Token String, Header, description 认证 Token),)### 3. 响应体与状态码rustresponses((status 200, description OK, body User),(status 400, description Bad Request, body ErrorResponse),(status 401, description Unauthorized),)### 4. 数据模型所有作为 body 的 struct 都要 derive ToSchema:rust#[derive(Serialize, Deserialize, ToSchema)]struct Foo { ... }需要额外示例时可以加 #[schema(example ...)]:rust#[derive(ToSchema)]struct User {#[schema(example 1)]id: i64,#[schema(example alice)]name: String,}### 5. 分组多个模块(常用)当接口很多时,把 OpenApi 拆成多个:rust#[derive(OpenApi)]#[openapi(paths(list_users, get_user), tags((name user)))]struct UserApi;#[derive(OpenApi)]#[openapi(paths(list_orders, create_order), tags((name order)))]struct OrderApi;#[derive(OpenApi)]#[openapi(nest((path /api, api UserApi),(path /api, api OrderApi),),components(schemas(User, Order)))]struct ApiDoc;### 6. 路由嵌套 (web::scope)rustHttpServer::new(|| {App::new().service(SwaggerUi::new(/swagger-ui/{_:.*}).url(/api-docs/openapi.json, ApiDoc::openapi()),).service(web::scope(/api).service(list_users).service(get_user))})注意:path /users 里写**完整路径**(/api/users)。---## 四、常见坑1. **path 必须和注解路由一致** — 否则 Swagger UI 上显示的路径不可用。2. **Body struct 必须 derive ToSchema 且 Serialize/Deserialize**,否则无法序列化示例。3. **泛型/嵌套类型** 需要用 #[schema(value_type ...)] 手动指定。4. **v5 版本** utoipa-actix-web 独立后,SwaggerUi 初始化方式有变化,注意版本对应。5. **{id} 路径参数** 用 Path,不要用 Query。---## 五、v5 的写法差异(简要)rustuse utoipa_actix_web::{AppExt, scope};use utoipa_swagger_ui::SwaggerUi;HttpServer::new(|| {App::new().into_utoipa_app().openapi(ApiDoc::openapi()).service(list_users).openapi_service(|api| {SwaggerUi::new(/swagger-ui/{_:.*}).url(/api-docs/openapi.json, api)}).into_app()})---**总结**:核心是三个东西 —— ToSchema(数据模型)、#[utoipa::path](接口描述)、#[derive(OpenApi)](聚合文档),再用 SwaggerUi service 挂载即可。上手成本很低,是 Actix-Web 生态里最成熟的 OpenAPI 方案。