framework
framework/fastapi/schema/response-model-required.md
medium
fastapi-schema-response-model
@router 必带 response_model — 类型即文档。Use when 写 Python 后端代码 / 评审涉及 `response-model-required` 的 PR。
response_model@router.post@router.get类型即文档
paths
backend/routers/**/*.pypy/routers/**/*.py
FastAPI Schema · response_model 必填
规则
每个 @router.<method> 装饰器必须带 response_model=...。这是 FastAPI 文档生成、类型检查、序列化的统一入口。
标准
@router.post("/create", response_model=JsonData[PresentationResp])
async def create(req: PresentationCreateReq, user=Depends(get_current_user)):
result = await service_create(req, user["account_id"])
return JsonData.success(result)
JsonData 统一包装
# backend/core/response.py
from typing import Generic, TypeVar
from pydantic import BaseModel, Field
T = TypeVar("T")
class JsonData(BaseModel, Generic[T]):
success: bool = Field(True, description="是否成功")
data: T | None = Field(None, description="业务数据")
msg: str | None = Field(None, description="提示信息")
code: int | None = Field(None, description="业务错误码")
@classmethod
def success(cls, data: T, msg: str | None = None):
return cls(success=True, data=data, msg=msg)
@classmethod
def error(cls, msg: str, code: int = 400):
return cls(success=False, msg=msg, code=code)
OpenAPI 文档自动生成
response_model 让 FastAPI 自动生成 OpenAPI schema,前端能根据 /docs 看到准确类型:
GET /docs → Swagger UI
GET /redoc → ReDoc UI
GET /openapi.json → 原始 schema
SSE 流式 response_model
SSE 不能用 response_model(流式不固定 schema),改用注释 + 文档:
@router.post(
"/stream",
response_class=StreamingResponse,
responses={200: {"content": {"text/event-stream": {}}}},
)
async def stream_outline(req: OutlineGenReq) -> StreamingResponse:
return StreamingResponse(generate_outline_stream(req), media_type="text/event-stream")
反例
# ❌ 无 response_model
@router.post("/create")
async def create(req: ...) -> Any:
return {"id": ..., "title": ...}
# 后果:
# 1. OpenAPI 文档缺类型
# 2. 返回字段未被 Pydantic 过滤(可能泄露内部字段)
# 3. 类型检查无法捕捉错误
自检
- [ ] 每个 endpoint 都有 response_model?
- [ ] 用
JsonData[T]统一包装? - [ ] SSE 用 response_class + responses 注释?
- [ ] /docs 能看到完整 schema?