速读#
这篇不是 FastAPI 教程,而是解释为什么在“快速写规整接口”这个阶段,我选 FastAPI 而不是 Flask。核心判断是自由和定型的取舍:Flask 给自由,FastAPI 用类型注解把接口定义、参数校验和自动文档提前固定下来。
打动我的点:一份注解管三处#
@app.get("/items/{item_id}")def read_item(item_id: int, q: str | None = None): return {"item_id": item_id, "q": q}启动后打开 /docs,Swagger UI 自动生成能直接点按钮测的交互文档。第一次见,真心惊艳。
靠的是类型注解:item_id: int 既做参数校验(非数字 → 422),又生成文档字段类型。一份注解,三处受益(定义、校验、文档)。
请求体是同一套逻辑,换成 Pydantic 模型:
class Item(BaseModel): name: str price: float
@app.post("/items")def create_item(item: Item): return item字段缺了、类型不对,根本进不了我的函数——FastAPI 在门口就用 422 拦下,并告诉调用方错在哪个字段。校验失败的处理代码,我一行都没写。
文档也不止 Swagger UI 一个壳:/redoc 是另一份阅读视图,背后是同一份 OpenAPI JSON——前端可以拿它直接生成调用代码。文档不再是写完接口后补的作业,而是接口定义的副产品——路径、参数、类型、必填与否这些形状层面的信息想脱节都脱节不了,能过期的只剩手写的那部分描述文字。
FastAPI vs Flask#
| Flask | FastAPI | |
|---|---|---|
| 校验 / 文档 | 额外自己补 | 从类型注解派生 |
| 气质 | 自由组装 | 接口该有的样子已定型 |
| 我何时选 | 自由度极高的小服务 | 快速写一堆规整接口 |
Flask 灵活,代价是「接口该有的规矩」全压在自己手上。Flask 生态当然也能凑出同样的东西——marshmallow 做校验、flasgger 出文档——但那是三件事各自选型、各自维护、各自可能脱节;FastAPI 里它们是同一份注解的三个输出。把类型注解当单一事实源,契约就不会散架。
定型也有代价,这不是稻草人:原型期字段变动频繁,每改一个字段都要动模型定义;确实存在要透传任意 JSON 的场景,硬套模型反而别扭。Flask 的自由在这些场景是真实价值。所以那个问句才成立——要自由还是要定型,是场景在回答,不是框架在比高下。
顺带交代一句:FastAPI 常被拿来说的还有 async 性能,但那不是我这个节点的理由。我的接口量级离「瓶颈在框架」远得很——为还不存在的流量挑性能,等于把选型理由让给宣传页。
没有绝对更好。问自己:这个场景要的是自由,还是定型?答案不同,选的就不同。
小取舍#
pip install fastapi "uvicorn[standard]"
# 开发uvicorn main:app --reload
# 生产:不要 --reload;[standard] 带上性能依赖| 场景 | 选择 |
|---|---|
| 本地试 | 可以不加 [standard] |
| 生产 | 加上;且去掉 --reload |
开发态要轻,生产态要稳——同一套东西,环境不同选择不同。
第一个接口从零跑到浏览器里看到自己的 JSON,反馈感很强。但这篇真正想留的是取舍框架:
选框架先问:我这个场景要的是自由还是定型。
