FastAPI 最令人惊叹的特性之一,就是它能根据你的代码和类型提示,100% 自动生成符合 OpenAPI 标准的交互式 API 文档。
这意味着你永远不需要手动编写或同步 API 文档。代码即文档(Documentation as Code),修改代码的同时,文档自动更新。
下面我将带你从基础访问到深度定制,全面掌握 FastAPI 的交互式文档功能。
一、 开箱即用的两大文档界面
启动你的 FastAPI 应用后,可以直接访问以下两个路径:
- Swagger UI (
http://127.0.0.1:8000/docs)
- 特点:交互式极强。你可以直接点击 “Try it out”,填入参数,发送真实的 HTTP 请求,并查看响应结果、状态码和 cURL 命令。
- 适用场景:日常开发、前后端联调、快速测试接口。
- ReDoc (
http://127.0.0.1:8000/redoc)
- 特点:静态、美观、三栏布局(导航、描述、请求/响应示例)。不支持直接发送请求,但阅读体验极佳。
- 适用场景:作为对外发布的官方 API 参考手册。
二、 深度定制:让你的文档专业且优雅
默认的文档虽然能用,但通过简单的配置,可以使其达到企业级标准。
1. 全局元数据配置 (App 级别)
在创建 FastAPI 实例时,传入元数据,这些信息会显示在文档的顶部。
from fastapi import FastAPI
app = FastAPI(
title="🚀 我的电商 API",
description="这是一个用于管理商品和用户的后端服务,基于 FastAPI 构建。",
version="1.0.0",
contact={
"name": "开发团队",
"email": "dev@example.com",
"url": "https://example.com",
},
license_info={
"name": "Apache 2.0",
"url": "https://www.apache.org/licenses/LICENSE-2.0.html",
},
# 自定义文档路径 (可选)
docs_url="/api-docs", # 将 Swagger UI 改为 /api-docs
redoc_url="/api-redoc", # 将 ReDoc 改为 /api-redoc
openapi_url="/openapi.json" # OpenAPI schema 的路径
)
@app.get("/")
def read_root():
return {"message": "查看文档请访问 /api-docs"}2. 路由级别的描述 (Summary & Description)
使用 summary(简短摘要)和 description(详细说明,支持 Markdown 语法)来丰富单个接口的文档。
@app.get(
"/items/{item_id}",
summary="获取商品详情",
description="""
根据商品 ID 获取详细信息。
- **item_id**: 必须是正整数。
- 如果商品不存在,将返回 404 错误。
- 支持通过 `q` 参数进行模糊搜索。
""",
tags=["商品管理"] # 用于在文档左侧对接口进行分组
)
def get_item(item_id: int, q: str | None = None):
return {"item_id": item_id, "query": q}3. 提供请求/响应示例 (Examples) 🌟
这是提升开发者体验(DX)的杀手锏。在 Pydantic 模型中使用 Field 的 examples 参数,Swagger UI 会自动填充这些示例数据,前端开发者一键即可测试。
(注意:以下使用 Pydantic V2 语法)
from pydantic import BaseModel, Field
class UserCreate(BaseModel):
username: str = Field(
...,
min_length=3,
max_length=50,
description="用户的登录名",
examples=["alice_2024", "bob_dev"]
)
email: str = Field(
...,
description="用户的电子邮箱",
examples=["alice@example.com"]
)
age: int | None = Field(
default=None,
ge=18,
description="用户年龄 (可选)",
examples=[25, 30]
)
@app.post("/users/", response_model=UserCreate, tags=["用户管理"])
def create_user(user: UserCreate):
return user效果:在 /docs 中点击该接口,请求体输入框会自动填入 {"username": "alice_2024", "email": "alice@example.com", "age": 25}。
4. 自定义响应状态码文档
默认情况下,FastAPI 会记录 200 状态码。你可以使用 responses 参数明确告诉文档其他可能的状态码及其含义。
from fastapi import HTTPException, status
@app.get(
"/items/{item_id}",
responses={
404: {"description": "商品未找到"},
400: {"description": "无效的 Item ID"}
}
)
def get_item_detail(item_id: int):
if item_id < 0:
raise HTTPException(status_code=400, detail="无效的 Item ID")
if item_id != 1:
raise HTTPException(status_code=404, detail="商品未找到")
return {"item_id": item_id, "name": "Laptop"}三、 高级技巧:在文档中集成安全认证
如果你的 API 需要鉴权,FastAPI 会自动在文档右上角生成一个 “Authorize” (授权) 按钮。
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
app = FastAPI()
security = HTTPBearer()
def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security)):
if credentials.credentials != "super-secret-token":
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="无效的 Token",
headers={"WWW-Authenticate": "Bearer"},
)
return {"username": "admin"}
@app.get("/protected-data")
def protected_route(user: dict = Depends(get_current_user)):
return {"message": f"欢迎, {user['username']}! 这是机密数据。"}效果:在 /docs 中,你可以点击 “Authorize”,输入 super-secret-token,之后该接口发出的所有请求都会自动在 Header 中带上 Authorization: Bearer super-secret-token。
四、 生产环境:如何隐藏文档?
在正式的生产环境中,出于安全考虑,你可能不希望暴露 API 文档。只需在创建 FastAPI 实例时将 URL 设置为 None 即可:
# 生产环境配置
app = FastAPI(
docs_url=None, # 禁用 Swagger UI
redoc_url=None, # 禁用 ReDoc
openapi_url=None # 禁用 OpenAPI schema 下载 (可选,但某些客户端可能依赖它)
)(最佳实践:通过环境变量控制,如 docs_url="/docs" if settings.ENV == "dev" else None)
五、 总结:FastAPI 文档的最佳实践清单
- 始终使用类型提示 (Type Hints):这是自动生成文档的基石。
- 善用
description和examples:把文档当成给前端/第三方开发者的“产品说明书”来写。 - 使用
tags对接口进行逻辑分组:当接口超过 10 个时,分组能极大提升文档的可读性。 - 利用
responses明确错误码:让调用者清楚知道在什么情况下会收到 4xx 或 5xx 错误。
你可以尝试在你现有的 FastAPI 项目中,为一个接口添加 summary、description 和 examples,然后刷新 /docs 页面,立刻就能看到专业级的文档效果!
如果你在定制文档时遇到任何问题(例如:如何为复杂的嵌套模型添加示例),随时告诉我!