万步健康app
77.51MB · 2025-09-10
FastAPI 的依赖注入系统是其核心特性之一,它允许你将复杂依赖关系解耦并重用代码。例如数据库连接、授权验证等场景:
# 示例:基本依赖注入
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_params(limit: int = 100, offset: int = 0):
return {"limit": limit, "offset": offset}
@app.get("/items/")
async def read_items(params: dict = Depends(common_params)):
return {"params": params}
在单元测试中,需要覆盖真实依赖(如数据库连接),避免对实际服务产生影响。使用 FastAPI 的 dependencies_overrides
:
# 测试覆盖真实数据库的示例
from fastapi.testclient import TestClient
from .main import app, get_db # 原始依赖
client = TestClient(app)
# 创建虚假的数据库依赖
async def fake_db():
return MockDatabase()
# 覆盖原始依赖
app.dependency_overrides[get_db] = fake_db
def test_read_items():
response = client.get("/items")
assert response.status_code == 200
graph TD
A[路由处理函数] --> B[依赖A]
A --> C[依赖B]
B --> D[子依赖A1]
C --> E[子依赖B1]
D --> F[数据库连接]
E --> F[数据库连接]
style F fill:#f9f,stroke:#333
要特别注意底层依赖的覆盖,比如共享的数据库连接对象:
# 覆盖共享资源
class MockDBConnection:
async def execute(self, query):
return ["mock_data"]
def override_db():
return MockDBConnection()
app.dependency_overrides[get_db_connection] = override_db
当需要调用外部 API 时,可能遇到:
from httpx import AsyncClient, Request, Response
class LoggingClient(AsyncClient):
async def send(self, request: Request, **kwargs) -> Response:
print(f"Sending: {request.method} {request.url}")
return await super().send(request, **kwargs)
# 在路由中使用
@app.get("/external")
async def external_data(
client: LoggingClient = Depends(lambda: LoggingClient())
):
response = await client.get("https://api.example.com/data")
return response.json()
flowchart LR
A[业务代码] --> B{拦截器检查}
B -->|服务正常| C[调用真实API]
B -->|服务异常| D[返回缓存数据]
B -->|测试模式| E[返回模拟数据]
# 完整的拦截器实现
import httpx
from fastapi import Depends
class ResilientClient(AsyncClient):
def __init__(self, mock_mode=False):
self.mock_mode = mock_mode
async def send(self, request: Request, **kwargs) -> Response:
if self.mock_mode:
return self.create_mock_response(request)
try:
return await super().send(request, timeout=10, **kwargs)
except httpx.ConnectError:
return self.return_fallback_data(request)
def create_mock_response(self, request):
return Response(200, json={"mock": "data"})
def return_fallback_data(self, request):
return Response(503, json={"error": "Service unavailable"})
问题: 当覆盖多层依赖时,需要特别注意哪种共享资源的处理?
答案: 共享的数据库连接对象。如果上层依赖和下层依赖使用了相同的数据库连接,需要确保整个链路上的依赖都被正确覆盖,否则可能造成依赖泄漏。
问题: 当第三方服务返回 503 错误时,我们的拦截器会如何响应?
答案: 通过 return_fallback_data
方法返回 503 响应和降级数据。这实现了请求降级,避免因外部服务问题导致整个应用不可用。
422 Unprocessable Entity
产生原因:
# 检查模型定义
class Item(BaseModel):
name: str # 确保没有类型错误
price: float
# 添加验证提示
@app.exception_handler(RequestValidationError)
async def validation_handler(request, exc):
return JSONResponse(
status_code=400,
content=jsonable_encoder({"detail": exc.errors()})
)
500 Internal Server Error in Dependency
产生原因:
# 增加依赖项的异常处理
async def secure_dependency():
try:
yield connection
except Exception:
raise HTTPException(500, "Dependency error")
finally:
clean_up_resources()
# 确认测试中执行了覆盖
app.dependency_overrides[real_dependency] = mock_dependency
TimeoutError in HTTP Client
产生原因:
# 设置合理超时时间
client = ResilientClient(timeout=5.0)
# 添加重试机制
import backoff
@backoff.on_exception(backoff.expo, httpx.RequestError)
async def safe_request(url):
return await client.get(url)