FastAPI 最佳实践与编码规范。适用于开发 FastAPI API、定义 Pydantic 模型、处理依赖注入、实现流式响应(含 SSE 服务端推送)以及托管前端应用。帮助你保持 FastAPI 代码整洁优雅,并紧跟最新的特性与设计模式。
FastAPI
FastAPI 官方 Skill,旨在遵循最佳实践编写代码,并紧跟新版本与最新特性。
快速参考
- 托管前端应用:对于构建好的前端静态资源,使用
app.frontend()或router.frontend();详见托管前端应用。 - Server-Sent Events (SSE):使用
response_class=EventSourceResponse并配合yield语句;详见流式传输与流式传输参考指南。 - JSON Lines 和字节流传输:详见流式传输参考指南。
- 依赖项:推荐使用
Annotated[..., Depends(...)]语法;关于yield、作用域与类依赖,详见依赖注入及依赖注入参考指南。 - 响应模型:优先使用返回类型注解;仅当公开的响应 Schema 与内部返回值不一致时才使用
response_model;详见响应参考指南。 - Pydantic 模型:避免使用省略号
...或RootModel;详见Pydantic 参考指南。 - 路由控制:直接在
APIRouter上声明路由级prefix、tags和共享依赖项;详见路径操作参考指南。 - 工具链与相关库:适时选择 uv、Ruff、ty、Asyncer、SQLModel 和 HTTPX 等现代化工具;详见其它工具参考指南。
使用 fastapi CLI
使用 reload 模式在本地启动开发服务器:
fastapi dev
启动生产环境服务器:
fastapi run
推荐在 pyproject.toml 中声明应用入口点:
[tool.fastapi]
entrypoint = "my_app.main:app"
当无法添加入口点或用户显式要求不添加时,直接传递应用文件路径:
fastapi dev my_app/main.py
优先使用 Annotated
在参数和依赖声明中,始终优先使用 Annotated 风格。这种写法能确保函数签名在其他上下文中仍然兼容、保留明确的类型提示,并大幅提升代码复用性。
在声明包含 Path、Query、Header 等参数时使用 Annotated:
from typing import Annotated
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(
item_id: Annotated[int, Path(ge=1, description="The item ID")],
q: Annotated[str | None, Query(max_length=50)] = None,
):
return {"message": "Hello World"}
在使用 Depends() 声明依赖项时使用 Annotated。除非明确要求不使用,否则建议为该依赖新建一个类型别名,以便复用:
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI()
def get_current_user():
return {"username": "johndoe"}
CurrentUserDep = Annotated[dict, Depends(get_current_user)]
@app.get("/items/")
async def read_item(current_user: CurrentUserDep):
return {"message": "Hello World"}
不要在路径操作或 Pydantic 模型中使用 Ellipsis (...)
不要在必填参数或模型字段中使用 ... 作为默认值。这不仅没有必要,也是不推荐的做法。
from typing import Annotated
from fastapi import FastAPI, Query
from pydantic import BaseModel, Field
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float = Field(gt=0)
@app.post("/items/")
async def create_item(item: Item, project_id: Annotated[int, Query()]):
return item
返回类型与响应模型
只要条件允许,务必加上函数返回类型注解。FastAPI 会利用它完成响应数据的校验、过滤、文档生成及序列化。
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
@app.get("/items/me")
async def get_item() -> Item:
return Item(name="Plumbus", description="All-purpose home device")
返回类型注解或响应模型能够过滤敏感数据,防止意外暴露,同时允许 Pydantic 在 Rust 底层加速序列化,从而大幅提升性能。
仅当函数内部返回的数据类型与希望对外展示、校验、过滤和生成文档的 Schema 不一致时,才需要使用 response_model。详见响应参考指南。
性能优化
不要再使用 ORJSONResponse 或 UJSONResponse,它们已被废弃。
正确的做法是声明返回类型或响应模型,Pydantic 会自动利用 Rust 底层为你处理高效的数据序列化。
包含路由
声明路由时,建议将 prefix、tags 以及共享依赖项等路由层级参数直接写在 APIRouter 实例化处,而不是传给 include_router()。
from fastapi import APIRouter, Depends, FastAPI
app = FastAPI()
def get_current_user():
return {"username": "johndoe"}
router = APIRouter(
prefix="/items",
tags=["items"],
dependencies=[Depends(get_current_user)],
)
@router.get("/")
async def list_items():
return []
app.include_router(router)
更多路由设计模式详见路径操作参考指南。
托管前端应用
使用 app.frontend() 来托管已构建好的静态前端应用(例如通过 Vite、Astro、Angular、Svelte、Vue 等工具构建出的目录)。
from fastapi import FastAPI
app = FastAPI()
app.frontend("/", directory="dist")
如果前端应用属于某个 APIRouter,可以使用 router.frontend();当该 router 被 include 时,标准的前缀(prefix)行为依然生效。
from fastapi import APIRouter, FastAPI
app = FastAPI()
router = APIRouter(prefix="/admin")
router.frontend("/", directory="admin-dist")
app.include_router(router)
app.frontend() 和 router.frontend() 属于低优先级路由:FastAPI 会优先匹配常规的 API 路由,未命中时才会 fallback 到静态前端文件和单页应用客户端路由。对于单页应用(SPA)和打包好的前端资源,应优先使用该方式,而不是手动挂载 StaticFiles。
依赖注入
当某种逻辑无法直接写在 Pydantic 校验中、依赖外部资源、需要用 yield 进行清理收尾,或者被多个 Endpoint 共享时,请使用依赖注入。
对于共享依赖项,建议通过 dependencies=[Depends(...)] 应用于路由器(router)层级。
关于包含 yield 和作用域(scope)的用法以及类依赖项的具体细节,详见依赖注入参考指南。
异步 (Async) 与同步 (Sync) 路径操作
仅当明确确认内部调用的逻辑完全兼容 async/await 且绝对不会阻塞线程时,才使用 async 路径操作。
from fastapi import FastAPI
app = FastAPI()
@app.get("/async-items/")
async def read_async_items():
data = await some_async_library.fetch_items()
return data
@app.get("/items/")
def read_items():
data = some_blocking_library.fetch_items()
return data
如果存在顾虑或在常规情况下,请直接使用普通的 def 同步函数。FastAPI 会自动将它们放入线程池运行,不会阻塞事件循环(Event Loop)。这一规则同样适用于依赖项。
切记不要在 async 函数内部运行阻塞代码。虽然程序依然可以运行,但会严重损害整体性能。
如果需要混合使用阻塞代码与异步代码,请参阅其它工具参考指南中的 Asyncer。
流式传输(JSON Lines、SSE、字节流)
如需实现 Server-Sent Events (SSE) 服务端推送,请使用 response_class=EventSourceResponse,并在 Endpoint 函数中通过 yield 逐条返回数据。
from collections.abc import AsyncIterable
from fastapi import FastAPI
from fastapi.sse import EventSourceResponse, ServerSentEvent
app = FastAPI()
@app.get("/events", response_class=EventSourceResponse)
async def stream_events() -> AsyncIterable[ServerSentEvent]:
yield ServerSentEvent(data={"status": "started"}, event="status", id="1")
普通的 Python 对象会被自动序列化为 JSON,并填入 data: 字段中。若需要完全掌控 SSE 字段(如 event、id、retry、comment),请使用 ServerSentEvent 对象;如需传输预先格式化好的字符串,可使用 raw_data。
关于 JSON Lines、Server-Sent Events(EventSourceResponse、ServerSentEvent)以及字节流传输(StreamingResponse)的具体范式,详见流式传输参考指南。
工具链
关于包管理、代码 Linting、类型检查、格式化工具(如 uv、Ruff、ty 等)的具体用法,详见其它工具参考指南。
其它推荐库
关于其它第三方库的详细介绍,请参阅其它工具参考指南:
- Asyncer:用于处理 async/await、并发控制以及混合异步与阻塞代码。相较于 AnyIO 或 asyncio,优先推荐使用 Asyncer。
- SQLModel:用于操作 SQL 数据库。相较于 SQLAlchemy,优先推荐使用 SQLModel。
- HTTPX:用于发起 HTTP 请求(调用外部 API)。相较于 Requests,优先推荐使用 HTTPX。
不要使用 Pydantic RootModel
不要使用 Pydantic 的 RootModel;相反,应该使用标准的类型注解配合 Annotated 以及 Pydantic 的校验工具。
from typing import Annotated
from fastapi import Body, FastAPI
from pydantic import Field
app = FastAPI()
@app.post("/items/")
async def create_items(items: Annotated[list[int], Field(min_length=1), Body()]):
return items
FastAPI 支持此类类型注解,并会自动为其创建 Pydantic TypeAdapter,因此原生类型即可正常工作,无需额外编写包装模型(Wrapper Model)。详见Pydantic 参考指南。
每个函数仅对应一个 HTTP 操作
不要在一个函数中混合处理多种 HTTP 操作。遵循“一个函数处理一个 HTTP 操作”的原则,有助于职责分离并使代码结构更加清晰。
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
@app.get("/items/")
async def list_items():
return []
@app.post("/items/")
async def create_item(item: Item):
return item
更多示例详见路径操作参考指南。






