FastAPI依赖注入:参数共享与逻辑复用

avatar
image image

扫描二维码关注或者微信搜一搜:编程智域 前端至全栈交流与成长


第一章:依赖注入核心原理

1.1 依赖树构建机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from fastapi import Depends


def auth_service():
return OAuth2Scheme()


def db_conn(auth: dict = Depends(auth_service)):
return Database(creds=auth)


@app.get("/data")
async def get_data(conn=Depends(db_conn)):
return conn.query()

依赖树可视化

1
2
graph TD
get_data --> db_conn --> auth_service

1.2 作用域控制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from fastapi import Depends, FastAPI
from sqlalchemy.orm import sessionmaker

SessionLocal = sessionmaker(autocommit=False)


# 请求级作用域
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()


# 应用级单例
cache = LRUCache(size=100)


def get_cache():
return cache

第二章:Pydantic深度集成

2.1 动态模型注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pydantic import create_model


def dynamic_model(fields: dict):
return create_model('DynamicModel', **fields)


class FilterFactory:
@classmethod
def create(cls, model: BaseModel):
class QueryParams(model):
limit: int = 100
offset: int = 0

return QueryParams


@app.get("/search")
async def search(params=Depends(FilterFactory.create(User))):
return params.dict()

2.2 校验逻辑复用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pydantic import validator, root_validator


class GeoValidator:
@classmethod
def lat_validator(cls, v):
if not -90 <= v <= 90:
raise ValueError("纬度范围错误")
return v


class Location(BaseModel):
lat: float
lng: float

_validate_lat = validator('lat', allow_reuse=True)(GeoValidator.lat_validator)

第三章:高级注入模式

3.1 工厂模式注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class NotificationClient:
def __init__(self, type: str):
self.client = self._create_client(type)

@staticmethod
def _create_client(type):
return {
"sms": SMSClient(),
"email": EmailClient()
}[type]


def get_notifier(type: str):
def _factory():
return NotificationClient(type)

return _factory


@app.post("/alert")
async def send_alert(
notifier: NotificationClient = Depends(get_notifier("sms"))
):
notifier.client.send()

3.2 条件依赖注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from fastapi import Header


def feature_flag_dep(feature_name: str):
class FeatureChecker:
def __init__(self,
enabled: bool = Depends(check_feature_enabled)
):
if not enabled:
raise HTTPException(403, "功能未启用")

return FeatureChecker


def check_feature_enabled(
feature: str = Header(...),
config: Config = Depends(get_config)
) -> bool:
return config.is_enabled(feature)


@app.get("/beta")
async def beta_feature(
checker=Depends(feature_flag_dep("beta"))
):
return "功能可用"

第四章:错误处理与调试

4.1 依赖链错误传播

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class DatabaseError(Exception):
pass


def db_dep():
try:
yield connection
except Exception as e:
raise DatabaseError() from e


@app.exception_handler(DatabaseError)
async def handle_db_error(request, exc):
return JSONResponse(500, {"detail": "数据库异常"})

4.2 依赖图可视化调试

1
2
3
4
5
6
7
8
9
10
11
from fastapi.dependencies.utils import solve_dependencies


def print_dependency_tree():
routes = app.routes
for route in routes:
if isinstance(route, APIRoute):
solved = solve_dependencies(route.dependant)
print(f"Route {route.path}:")
for dep in solved.flat_graph():
print(f"└─ {dep.call.__name__}")

第五章:测试与维护

5.1 依赖覆盖测试

1
2
3
4
5
6
7
8
9
10
11
12
from fastapi.testclient import TestClient


def override_dep():
return MockDatabase()


app.dependency_overrides[get_db] = override_dep

client = TestClient(app)
response = client.get("/data")
assert "mock" in response.text

5.2 依赖版本管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from packaging.version import parse


class VersionedDep:
def __init__(self, api_version: str = Header(...)):
self.version = parse(api_version)

def check_min_version(self, min_version: str):
if self.version < parse(min_version):
raise HTTPException(400, "版本过低")


@app.get("/new-feature")
async def new_feature(
dep: VersionedDep = Depends(),
checker=Depends(dep.check_min_version("2.3"))
):
return "功能可用"

课后Quiz

Q1:如何实现跨路由共享查询参数?
A) 在每个路由重复定义参数
B) 使用全局变量存储参数
C) 通过依赖注入共享参数

Q2:依赖注入的yield语句有什么作用?

  1. 实现请求后清理逻辑
  2. 提高依赖执行速度
  3. 支持异步生成器

Q3:如何测试被覆盖的依赖项?

  • 使用dependency_overrides
  • 直接修改源代码
  • 配置环境变量

错误解决方案速查表

错误类型解决方案
422 Validation Error检查请求参数是否匹配Pydantic模型定义
DIResolutionError确认依赖树没有循环引用,所有依赖项已正确定义
DependencyInstantiationError检查yield依赖是否正确处理异常,验证上下文管理器实现

扩展阅读

  1. 《Dependency Injection Principles》 - 依赖注入设计原则深度解析
  2. 《Clean Architecture in Python》 - Python整洁架构实践指南
  3. 《FastAPI Internals》 - 框架源码分析与实现原理

架构箴言:优秀的依赖注入设计应遵循SOLID原则,特别是依赖倒置原则(DIP)。建议使用依赖图分析工具保持注入层次不超过5层,对高频依赖实施缓存策略,并定期进行依赖关系审计。

探索数千个预构建的 AI 应用,开启你的下一个伟大创意

余下文章内容请点击跳转至 个人博客页面 或者 扫码关注或者微信搜一搜:编程智域 前端至全栈交流与成长,阅读完整的文章:

往期文章归档: