Rust 用 utoipa 给 Axum 自动生成 OpenAPI 文档与 Swagger UI:代码即文档,无需手写

test12026-11-020 次阅读

文档不该靠手维护

Go 那边可以规范生成代码,Rust 这边走“代码即文档”更顺手。utoipa 用 derive 宏在结构体和方法上标注 schema,再配合 utoipa-swagger-ui 直接挂一个可交互的 Swagger 页面。改了结构体字段,文档自动跟着变,不会出现代码改了文档没动的情况。

定义带 schema 的结构体与接口

use axum::{routing::get, Json, Router};
use serde::{Deserialize, Serialize};
use utoipa::{OpenApi, ToSchema};
use utoipa_swagger_ui::SwaggerUi;

#[derive(Serialize, Deserialize, ToSchema)]
struct Article {
    id: i64,
    #[schema(example = "示例标题")]
    title: String,
    author: Option<String>,
}

#[utoipa::path(
    get,
    path = "/articles/{id}",
    params(("id" = i64, Path, description = "文章 ID")),
    responses((status = 200, description = "OK", body = Article))
)]
async fn get_article(id: i64) -> Json<Article> {
    Json(Article { id, title: "示例标题".into(), author: Some("张三".into()) })
}

#[derive(OpenApi)]
#[openapi(paths(get_article), components(schemas(Article)))]
struct ApiDoc;

把 Swagger UI 挂到路由

#[tokio::main]
async fn main() {
    let app = Router::new()
        .route("/articles/{id}", get(get_article))
        .merge(SwaggerUi::new("/swagger-ui")
            .url("/api-docs/openapi.json", ApiDoc::openapi()));

    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
    axum::serve(listener, app).await.unwrap();
}

启动后访问 /swagger-ui 就能看到自动生成的交互式文档,能直接填参数发请求。openapi.json 也可以单独导出交给前端或网关做契约校验。

几个实用技巧

  • 用 #[schema(example = ...)] 给字段加示例值,Swagger 里点一下就填好了,联调体验更好。
  • 枚举和可选字段直接靠 serde 的 skip_serializing_if 与 utoipa 的 required 推断,文档与运行时语义一致。
  • CI 里加一步导出 openapi.json 并提交,等于把“接口契约”纳入版本管理,前后端照着同一份跑。
T

test1

文章作者

文档不该靠手维护 Go 那边可以规范生成代码,Rust 这边走“代码即文档”更顺手。utoipa 用 derive 宏...

分类
技术
发布时间
2026-11-02
字数
约 1535 字
阅读
0 次