1. FastAPI 学习路线规划
作为一名长期使用 Python 进行后端开发的工程师,我最近系统性地学习了 FastAPI 框架。第二天学习的内容往往是最关键的转折点 - 从基础概念过渡到实际应用。这个阶段需要掌握的核心包括路由设计、请求处理、响应模型等实际开发中每天都会用到的功能。
FastAPI 的官方文档虽然全面,但对于新手来说信息量过大。我在学习过程中总结了一套高效的学习方法:先掌握 20% 的核心功能来解决 80% 的常见需求。第二天的学习重点就应该放在这些高频使用的特性上。
2. 路由系统深度解析
2.1 基础路由配置
FastAPI 的路由系统继承自 Starlette,但做了更符合现代 Python 特性的封装。一个典型的路由定义如下:
python复制from fastapi import FastAPI
app = FastAPI()
@app.get("/items/")
async def read_items():
return [{"name": "Item 1"}, {"name": "Item 2"}]
这里有几个关键点需要注意:
- 使用装饰器语法
@app.get()比传统的app.add_route()更符合 Python 风格 - 路径参数
/items/结尾的斜杠在 RESTful 规范中有特殊含义,代表这是一个集合资源 - 异步函数声明
async def是充分利用 FastAPI 性能优势的关键
提示:虽然 FastAPI 支持同步函数,但在 IO 密集型场景下始终优先使用异步函数以获得最佳性能。
2.2 路径参数与查询参数
FastAPI 的参数处理是其亮点之一,完全基于 Python 类型提示实现:
python复制from typing import Optional
@app.get("/items/{item_id}")
async def read_item(item_id: int, q: Optional[str] = None):
return {"item_id": item_id, "q": q}
这种设计带来了几个优势:
- 自动类型转换:URL 中的字符串
item_id会自动转换为整数类型 - 自动文档生成:参数信息会显示在自动生成的 API 文档中
- 输入验证:如果传入非数字的
item_id会自动返回 422 错误
我在实际项目中总结的参数使用经验:
- 必选参数放在路径中 (
/items/{item_id}) - 可选参数使用查询参数 (
?q=search) - 复杂参数考虑使用请求体 (后面会讲到)
3. 请求与响应模型
3.1 Pydantic 模型基础
FastAPI 的请求和响应模型都基于 Pydantic,这是一个提供运行时类型检查的库。定义一个简单的用户模型:
python复制from pydantic import BaseModel
class User(BaseModel):
username: str
email: str
full_name: Optional[str] = None
使用模型作为请求体:
python复制@app.post("/users/")
async def create_user(user: User):
return user
Pydantic 模型的几个实用特性:
- 自动验证输入数据是否符合类型声明
- 支持嵌套模型和复杂数据结构
- 提供
.dict()方法方便转换为字典
3.2 响应模型定制
FastAPI 允许显式声明响应模型,这在 API 设计中非常有用:
python复制@app.post("/users/", response_model=User)
async def create_user(user: User):
return user
这样设计的好处:
- 自动过滤响应中多余的字段
- 文档中明确显示返回数据结构
- 提供类型检查确保返回数据符合预期
踩坑记录:曾经因为忘记声明
response_model导致敏感字段泄露,建议所有路由都显式声明响应模型。
4. 错误处理与中间件
4.1 自定义异常处理
FastAPI 提供了灵活的异常处理机制:
python复制from fastapi import HTTPException
@app.get("/items/{item_id}")
async def read_item(item_id: int):
if item_id not in items:
raise HTTPException(status_code=404, detail="Item not found")
return {"item": items[item_id]}
更复杂的异常处理可以通过添加异常处理器实现:
python复制from fastapi import Request
from fastapi.responses import JSONResponse
@app.exception_handler(ValueError)
async def value_error_handler(request: Request, exc: ValueError):
return JSONResponse(
status_code=400,
content={"message": f"Value error: {str(exc)}"},
)
4.2 中间件使用实践
中间件是处理跨切面关注点(如日志、认证)的理想场所:
python复制import time
from fastapi import Request
@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
response.headers["X-Process-Time"] = str(process_time)
return response
实际项目中常用的中间件场景:
- 请求日志记录
- 认证和授权检查
- CORS 处理
- 响应时间监控
5. 依赖注入系统
5.1 基础依赖使用
FastAPI 的依赖注入系统是其最强大的特性之一:
python复制from fastapi import Depends
def common_parameters(q: Optional[str] = None, skip: int = 0, limit: int = 100):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items/")
async def read_items(commons: dict = Depends(common_parameters)):
return commons
依赖注入的优势:
- 代码复用:避免在每个路由函数中重复参数处理逻辑
- 可测试性:依赖项可以轻松替换为测试实现
- 清晰的结构:显式声明函数依赖关系
5.2 复杂依赖场景
依赖项本身也可以有依赖项,形成依赖链:
python复制def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
def get_current_user(db: Session = Depends(get_db)):
# 从数据库获取用户
return user
@app.get("/users/me")
async def read_user_me(current_user: User = Depends(get_current_user)):
return current_user
我在实际项目中的经验:
- 数据库会话管理最适合用依赖注入实现
- 认证逻辑应该封装为可复用的依赖项
- 避免创建过于复杂的依赖关系图
6. 测试驱动开发实践
6.1 编写测试用例
FastAPI 的测试客户端让 API 测试变得简单:
python复制from fastapi.testclient import TestClient
client = TestClient(app)
def test_read_item():
response = client.get("/items/42")
assert response.status_code == 200
assert response.json() == {"item_id": 42}
测试时的一些技巧:
- 使用
pytest作为测试框架 - 为每个路由编写成功和失败用例
- 测试边界条件和异常情况
6.2 测试覆盖率提升
为了提高测试质量,我通常会:
- 使用
pytest-cov检查测试覆盖率 - 重点测试业务逻辑而非框架代码
- 模拟外部依赖(如数据库)以加快测试速度
一个模拟数据库的测试示例:
python复制from unittest.mock import Mock
def test_read_item_mock():
mock_db = Mock()
mock_db.get.return_value = {"item_id": 42}
response = client.get("/items/42")
assert response.status_code == 200
7. 性能优化技巧
7.1 异步数据库访问
FastAPI 的性能优势在配合异步数据库驱动时最能体现:
python复制from databases import Database
database = Database("postgresql://user:password@localhost/db")
@app.on_event("startup")
async def startup():
await database.connect()
@app.on_event("shutdown")
async def shutdown():
await database.disconnect()
7.2 缓存策略实现
常用缓存方案:
- 内存缓存(如
cachetools) - Redis 缓存
- HTTP 缓存头
一个简单的内存缓存实现:
python复制from cachetools import TTLCache
cache = TTLCache(maxsize=100, ttl=300)
@app.get("/expensive-operation/")
async def expensive_operation():
if "result" in cache:
return cache["result"]
result = await do_expensive_operation()
cache["result"] = result
return result
8. 项目结构最佳实践
经过多个 FastAPI 项目实践,我总结出以下项目结构:
code复制my_project/
├── app/
│ ├── __init__.py
│ ├── main.py # 应用创建和配置
│ ├── dependencies.py # 依赖项定义
│ ├── routers/ # 路由模块
│ │ ├── items.py
│ │ └── users.py
│ ├── models/ # Pydantic 模型
│ └── db/ # 数据库相关
├── tests/ # 测试代码
└── requirements.txt # 依赖列表
这种结构的优势:
- 功能模块化,便于维护
- 清晰的关注点分离
- 易于扩展和测试
在第二天学习 FastAPI 时,最重要的是动手实践。我建议创建一个实际项目,逐步实现上述各个功能点。遇到问题时,FastAPI 的官方文档和活跃的社区都是极好的资源。