Rust Axum 框架中集成 OpenAPI (Swagger)

Rust Axum 框架中集成 OpenAPI (Swagger)
SoniaChenRust Axum 框架中集成 OpenAPI (Swagger)
1. 概述与目标
本指南详细介绍如何在基于 Rust 的 Axum 框架中,实现 OpenAPI (Swagger) 规范的集成。我们将采用 utoipa 库实现代码优先 (Code-first) 的 API 文档生成,并利用 utoipa-swagger-ui 部署交互式文档界面。
目标是实现清晰、自动化的 API 文档和测试界面,同时解决 Axum 0.7+ 版本与 utoipa-swagger-ui 9.x.x 版本的兼容性问题。
2. 技术选型与依赖配置
2.1 核心依赖
| 库名 | 版本 (示例) | 用途 | 关键特性 (Feature) |
|---|---|---|---|
utoipa |
5.4.0 | 核心库,用于通过宏注解生成 OpenAPI JSON 规范。 | axum_extras, serde_json |
utoipa-swagger-ui |
9.0.2 | 提供静态文件和路由,用于部署 Swagger UI 界面。 | axum |
serde |
1.0 | 数据结构序列化/反序列化。 | derive |
2.2 Cargo.toml 配置示例
[dependencies]
# ... 其他依赖 ...
serde = { version = "1.0", features = ["derive"] }
# OpenAPI
utoipa = { version = "5.4.0", features = ["axum_extras", "serde_json"] }
utoipa-swagger-ui = { version = "9.0.2", features = ["axum"] }
3. 代码结构建议
为了模块化和清晰地管理 API,建议采用以下结构:
| 路径 | 职责 |
|---|---|
src/api/ |
API 模块根目录 |
src/api/mod.rs |
模块入口,包含 OpenAPI 定义 (ApiDoc)。 |
src/api/models.rs |
包含所有请求和响应体的 数据结构体。 |
src/api/[feature].rs |
存放特定功能的 API 处理器函数 (handlers)。 |
4. utoipa 核心集成步骤
4.1 数据模型注解 (src/api/models.rs)
所有用于请求体或响应体的结构体都必须添加 #[derive(ToSchema)],这是 utoipa 识别数据类型的关键。
// 示例:健康检查响应和业务模型
use utoipa::ToSchema;
use serde::{Serialize, Deserialize};
#[derive(ToSchema, Serialize, Deserialize)]
#[aliases(Health = HealthStatus)] // 可选:提供更友好的 OpenAPI Schema 名称
pub struct HealthStatus {
pub status: String,
pub service: String,
pub version: String,
}
#[derive(ToSchema, Serialize, Deserialize)]
pub struct FeatureType {
pub id: u32,
pub name: String,
pub description: Option<String>,
}
#[derive(ToSchema, Serialize, Deserialize)]
pub struct SubmissionRequest {
pub value: u64,
pub feature_type_id: u32,
}
4.2 API 文档定义 (src/api/mod.rs)
使用 #[derive(OpenApi)] 宏创建文档入口点 (ApiDoc),配置元数据、数据模型和所有 API 路径。
use utoipa::OpenApi;
use crate::api::models::{HealthStatus, FeatureType, SubmissionRequest};
// 导入所有 handler 函数
#[derive(OpenApi)]
#[openapi(
// 1. 定义 API 的元数据
info(title = "通用 Axum API 文档", version = "v0.1.0"),
// 2. 引用所有用于文档的数据结构体
components(schemas(
HealthStatus,
FeatureType,
SubmissionRequest,
// ... 其他模型 ...
)),
// 3. 列出所有带有 #[utoipa::path(...)] 注解的 handler 函数
paths(
// 引用不同模块中的 handler 函数
crate::api::health::health_check,
crate::api::feature::get_feature_types,
// ... 其他 handler ...
),
// 4. 定义标签用于分组
tags(
(name = "Health", description = "健康检查"),
(name = "Feature", description = "通用功能"),
)
)]
pub struct ApiDoc;
4.3 处理器函数注解 (src/api/[feature].rs)
所有 API 处理器函数(Handlers)必须添加 #[utoipa::path(...)] 宏来定义路径、方法、参数和响应。文档注释 (///) 将作为方法的描述。
// 示例:GET /health
/// 获取服务健康状态
#[utoipa::path(
get,
path = "/health",
responses(
(status = 200, description = "Service is up and running", body = HealthStatus),
(status = 500, description = "Internal Server Error"),
),
tag = "Health"
)]
pub async fn health_check() -> Result<Json<HealthStatus>, StatusCode> {
// ... 逻辑实现 ...
todo!()
}
// 示例:GET /features
/// 获取所有可用功能类型
#[utoipa::path(
get,
path = "/features",
responses(
(status = 200, description = "返回功能列表", body = [FeatureType]),
),
tag = "Feature"
)]
pub async fn get_feature_types() -> Result<Json<Vec<FeatureType>>, StatusCode> {
// ... 逻辑实现 ...
todo!()
}
5. Axum 路由集成与兼容性修复
这是 Axum 0.7+ 和 utoipa-swagger-ui 9.0.2 集成的关键部分。
5.1 兼容性问题与解决方案
| 错误类型 | 原因 | 解决方案 (针对 v9.0.2) |
|---|---|---|
E0308 (mismatched types) |
Axum .merge() 无法推断 SwaggerUi 的类型。 |
在 SwaggerUi::new(...).url(...) 链的末尾显式调用 .into()。 |
panic (Nesting at the root) |
Axum 0.7+ 禁止使用 .nest("/", ...)。 |
移除根嵌套,直接将业务路由作为基础路由起点。 |
no method named into_make_service |
utoipa-swagger-ui 9.x.x 版本中,此类转换方法被移除。 |
改用 .into()。 |
5.2 路由集成代码示例 (src/main.rs)
use utoipa_swagger_ui::SwaggerUi;
use axum::Router;
async fn main() {
// 假设 create_router 是您的业务 API 路由函数
let app_router = create_router(state); // state 假设是应用状态
// 1. 创建 Swagger UI 路由
let swagger_router = SwaggerUi::new("/swagger-ui") // Swagger UI 访问路径
.url("/api-docs/openapi.json", ApiDoc::openapi()) // OpenAPI 规范文件路径
// 关键兼容性修复:将 SwaggerUi 转换为 Axum Router 可接受的类型。
.into();
// 2. 合并路由并应用中间件
let app = app_router
.merge(swagger_router) // 使用 merge 方法合并 Swagger 路由
.layer(cors); // 应用中间件(例如 CORS)
// ... 服务器启动 (listener 和 axum::serve) ...
}
6. 访问与验证
服务成功运行后,文档即可通过以下地址访问(假设默认端口为 8080):
| 访问目标 | URL | 作用 |
|---|---|---|
| Swagger UI 交互页面 | http://localhost:8080/swagger-ui |
提供可测试的交互式界面。 |
| OpenAPI 规范文件 | http://localhost:8080/api-docs/openapi.json |
原始的 JSON 格式 API 规范文件。 |







