| Crates.io | axum_doc |
| lib.rs | axum_doc |
| version | 0.2.3 |
| created_at | 2025-06-22 03:26:56.999389+00 |
| updated_at | 2026-01-13 08:55:27.214045+00 |
| description | A CLI tool to generate OpenAPI 3.0 JSON from Axum Rust projects. |
| homepage | https://github.com/ipconfiger/axum_doc |
| repository | https://github.com/ipconfiger/axum_doc |
| max_upload_size | |
| id | 1721259 |
| size | 156,800 |
A command-line tool for automatically generating OpenAPI 3.0 JSON specifications from Axum Rust projects through static code analysis.
Option<T> handling with OpenAPI nullable fieldVec<T> schema generation with item typesRouter::nest() with deep nesting support/// commentscargo install axum_doc
Requires Rust 1.65+ and ensure
cargois properly configured.
Run in your Axum project root directory:
axum_doc \
--base-dir . \
--handler-file src/main.rs \
--model-files src/form.rs,src/response.rs,src/types.rs \
--output openapi.json
--base-dir: Project root directory (default: current directory)--handler-file: Main route/handler file (default: src/main.rs)--model-files: Model definition files, comma-separated (default: src/form.rs,src/response.rs,src/types.rs)--output: Output OpenAPI JSON filename (default: openapi-bak.json)Given the following Axum code:
use axum::{Json, routing::post, Router};
use serde::{Deserialize, Serialize};
/// User login credentials
#[derive(Deserialize)]
pub struct LoginForm {
pub username: String,
pub password: String,
}
/// User login response with token
#[derive(Serialize)]
pub struct LoginResponse {
pub token: String,
pub user_id: uuid::Uuid,
pub username: String,
}
/// User login endpoint
///
/// Authenticates a user and returns a JWT token.
async fn login(Json(form): Json<LoginForm>) -> Json<LoginResponse> {
Json(LoginResponse {
token: "jwt_token".to_string(),
user_id: uuid::Uuid::new_v4(),
username: form.username,
})
}
fn app() -> Router {
Router::new().route("/login", post(login))
}
Run axum_doc to generate:
{
"openapi": "3.0.0",
"info": {
"title": "Generated API",
"version": "1.0.0"
},
"paths": {
"/login": {
"post": {
"summary": "User login endpoint",
"description": "Authenticates a user and returns a JWT token.",
"operationId": "login",
"requestBody": {
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/LoginForm" }
}
}
},
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/LoginResponse" }
}
}
}
}
}
}
},
"components": {
"schemas": {
"LoginResponse": {
"type": "object",
"properties": {
"token": { "type": "string" },
"user_id": {
"type": "string",
"format": "uuid"
},
"username": { "type": "string" }
}
}
}
}
}
| Rust Type | OpenAPI Type | Format |
|---|---|---|
String, &str |
string | - |
i32, u32 |
integer | int32 |
i64, u64, usize, isize |
integer | int64 |
f32 |
number | float |
f64 |
number | double |
bool |
boolean | - |
| Rust Type | OpenAPI Type | Format | Example |
|---|---|---|---|
uuid::Uuid |
string | uuid | 550e8400-e29b-41d4-a716-446655440000 |
chrono::DateTime |
string | date-time | 2024-01-01T00:00:00Z |
std::time::Duration |
string | duration | - |
| Rust Type | OpenAPI Type | Notes |
|---|---|---|
Vec<T> |
array | Items schema properly resolved |
Option<T> |
T | With nullable: true |
HashMap<K,V> |
object | With additionalProperties |
Router::new()
.nest("/api/v1", user::router()) // Path prefix automatically applied
⚠️ Anti-Pattern to Avoid:
Don't nest the same path prefix multiple times:
// In modules/mod.rs:
Router::new().nest("/api/v1/user", user::router())
// In modules/user/mod.rs (WRONG - causes /api/v1/user/api/v1/user/login):
Router::new().nest("/api/v1/user", handler::router())
// Correct approach - just return the handler router:
pub fn router() -> Router {
handler::router() // No double-nesting
}
Router::new()
.route("/", get(root))
.merge(auth::router()) // Cross-module composition
Use /// doc comments to document your endpoints:
/// Get user by ID
///
/// Retrieves user information by their unique identifier.
/// Returns 404 if the user doesn't exist.
async fn get_user(Path(id): Path<Uuid>) -> Json<User> {
// ...
}
summarydescriptionJson, Query, Path, Form.nest("/api/v1", module_router()) in both parent and child modules)current_module tracking to distinguish sibling vs nested modulescalculate_module_path() helper for accurate module path computationextract_module_from_path() helper to derive module context from file pathsmodules/auth/handler.rs)module_stack field (replaced by current_module)nullable: true instead of "object"additionalPropertiesThe project includes comprehensive tests:
# Run all tests
cargo test
# Run only unit tests
cargo test --bin axum_doc
# Run only integration tests
cargo test --test integration_test
MIT
axum_doc 是一个用于从 Axum Rust 项目自动生成 OpenAPI 3.0 JSON 规范的命令行工具,通过静态代码分析实现。
Option<T>,生成 OpenAPI nullable 字段Vec<T> schema 生成,包含元素类型Router::nest() 支持,支持深层嵌套/// 注释提取摘要和描述cargo install axum_doc
需要 Rust 1.65+,并确保
cargo已正确配置。
在你的 Axum 项目根目录下运行:
axum_doc \
--base-dir . \
--handler-file src/main.rs \
--model-files src/form.rs,src/response.rs,src/types.rs \
--output openapi.json
--base-dir:项目根目录(默认:当前目录)--handler-file:主路由/处理器文件(默认:src/main.rs)--model-files:模型定义文件,逗号分隔(默认:src/form.rs,src/response.rs,src/types.rs)--output:输出的 OpenAPI JSON 文件名(默认:openapi-bak.json)给定以下 Axum 代码:
use axum::{Json, routing::post, Router};
use serde::{Deserialize, Serialize};
/// 用户登录凭据
#[derive(Deserialize)]
pub struct LoginForm {
pub username: String,
pub password: String,
}
/// 用户登录响应
#[derive(Serialize)]
pub struct LoginResponse {
pub token: String,
pub user_id: uuid::Uuid,
pub username: String,
}
/// 用户登录端点
///
/// 验证用户身份并返回 JWT token。
async fn login(Json(form): Json<LoginForm>) -> Json<LoginResponse> {
Json(LoginResponse {
token: "jwt_token".to_string(),
user_id: uuid::Uuid::new_v4(),
username: form.username,
})
}
fn app() -> Router {
Router::new().route("/login", post(login))
}
运行 axum_doc 生成:
{
"openapi": "3.0.0",
"info": {
"title": "Generated API",
"version": "1.0.0"
},
"paths": {
"/login": {
"post": {
"summary": "用户登录端点",
"description": "验证用户身份并返回 JWT token。",
"operationId": "login",
"requestBody": {
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/LoginForm" }
}
}
},
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/LoginResponse" }
}
}
}
}
}
}
},
"components": {
"schemas": {
"LoginResponse": {
"type": "object",
"properties": {
"token": { "type": "string" },
"user_id": {
"type": "string",
"format": "uuid"
},
"username": { "type": "string" }
}
}
}
}
}
| Rust 类型 | OpenAPI 类型 | 格式 |
|---|---|---|
String, &str |
string | - |
i32, u32 |
integer | int32 |
i64, u64, usize, isize |
integer | int64 |
f32 |
number | float |
f64 |
number | double |
bool |
boolean | - |
| Rust 类型 | OpenAPI 类型 | 格式 | 示例 |
|---|---|---|---|
uuid::Uuid |
string | uuid | 550e8400-e29b-41d4-a716-446655440000 |
chrono::DateTime |
string | date-time | 2024-01-01T00:00:00Z |
std::time::Duration |
string | duration | - |
| Rust 类型 | OpenAPI 类型 | 说明 |
|---|---|---|
Vec<T> |
array | 正确解析元素类型 |
Option<T> |
T | 添加 nullable: true |
HashMap<K,V> |
object | 包含 additionalProperties |
Router::new()
.nest("/api/v1", user::router()) // 路径前缀自动应用
⚠️ 避免的反模式:
不要多次嵌套相同的路径前缀:
// 在 modules/mod.rs 中:
Router::new().nest("/api/v1/user", user::router())
// 在 modules/user/mod.rs 中(错误 - 会导致 /api/v1/user/api/v1/user/login):
Router::new().nest("/api/v1/user", handler::router())
// 正确的方法 - 直接返回 handler 的 router:
pub fn router() -> Router {
handler::router() // 避免双重嵌套
}
Router::new()
.route("/", get(root))
.merge(auth::router()) // 跨模块组合
使用 /// 文档注释来记录端点:
/// 根据 ID 获取用户
///
/// 通过唯一标识符检索用户信息。
/// 如果用户不存在,返回 404。
async fn get_user(Path(id): Path<Uuid>) -> Json<User> {
// ...
}
summarydescriptionJson、Query、Path、Form.nest("/api/v1", module_router()))current_module 跟踪以区分兄弟模块和嵌套模块calculate_module_path() 辅助函数用于精确计算模块路径extract_module_from_path() 辅助函数从文件路径推导模块上下文modules/auth/handler.rs)module_stack 字段(由 current_module 替代)nullable: true 而非 "object"additionalProperties项目包含全面的测试:
# 运行所有测试
cargo test
# 仅运行单元测试
cargo test --bin axum_doc
# 仅运行集成测试
cargo test --test integration_test
MIT