FastAPI 依賴注入(Depends):提高代碼復(fù)用性
FastAPI 是一個(gè)基于 Python 的現(xiàn)代 Web 框架,它不僅語(yǔ)法優(yōu)雅、支持異步,還擁有強(qiáng)大的依賴注入系統(tǒng)(Dependency Injection)。依賴注入能讓我們的代碼模塊化、職責(zé)單一、易于擴(kuò)展,也極大方便了自動(dòng)化測(cè)試。
本文將結(jié)合實(shí)際場(chǎng)景,系統(tǒng)講解如何在 FastAPI 中:
- 注入數(shù)據(jù)庫(kù)連接
- 注入權(quán)限校驗(yàn)
- 注入請(qǐng)求上下文
- 優(yōu)雅編寫單元測(cè)試
1. 數(shù)據(jù)庫(kù)連接依賴注入(以 Tortoise ORM 為例)
在 Web 應(yīng)用中,每個(gè)請(qǐng)求都需要與數(shù)據(jù)庫(kù)交互。我們不能將數(shù)據(jù)庫(kù)連接硬編碼在每個(gè)視圖中,而是通過依賴注入自動(dòng)管理事務(wù)生命周期。
示例:
# database.py
from tortoise.transactions import in_transaction
async def get_db():
async with in_transaction() as connection:
yield connection
通過 yield 的方式,每個(gè)請(qǐng)求都會(huì)自動(dòng)管理這個(gè)連接的生命周期,執(zhí)行完畢后自動(dòng)關(guān)閉。
使用方式:
# api/user.py
from fastapi import APIRouter, Depends
from database import get_db
router = APIRouter()
@router.get("/users")
async def get_users(db=Depends(get_db)):
return await db.execute_query_dict("SELECT * FROM user")
優(yōu)點(diǎn):
- 保證事務(wù)一致性
- 避免重復(fù)創(chuàng)建連接
- 易于測(cè)試(可替換 get_db)
2. 權(quán)限驗(yàn)證依賴注入
權(quán)限校驗(yàn)是每個(gè) Web 接口的“守門人”。通過 DI,可以實(shí)現(xiàn)靈活、統(tǒng)一的權(quán)限控制邏輯。
示例:
# auth.py
from fastapi import Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer
from models import User # 假設(shè)你有一個(gè) User 模型
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/login")
defdecode_token(token: str):
# 實(shí)際項(xiàng)目中請(qǐng)用 JWT 解碼
if token == "admin-token":
return {"id": 1, "is_admin": True}
elif token == "user-token":
return {"id": 2, "is_admin": False}
returnNone
asyncdefverify_token(token: str = Depends(oauth2_scheme)) -> int:
user = decode_token(token)
ifnot user:
raise HTTPException(status_code=401, detail="Invalid token")
return user["id"]
asyncdefadmin_required(user_id: int = Depends(verify_token)):
user = await User.get(id=user_id)
ifnot user.is_admin:
raise HTTPException(status_code=403, detail="Admin only")
return user
使用方式:
@app.get("/admin")
async def admin_dashboard(current_user=Depends(admin_required)):
return {"msg": f"Welcome admin {current_user.username}"}
優(yōu)點(diǎn):
- 權(quán)限邏輯集中管理
- 可靈活復(fù)用(普通用戶、管理員等)
- 更易調(diào)試和測(cè)試
3. 請(qǐng)求上下文注入(IP、UA、Headers)
如果你想記錄用戶 IP、來源、設(shè)備信息等,可以封裝一個(gè)請(qǐng)求上下文依賴。
示例:
# context.py
from fastapi import Request
async def get_request_context(request: Request):
return {
"ip": request.client.host,
"user_agent": request.headers.get("user-agent"),
"headers": dict(request.headers)
}
使用方式:
@app.get("/log")
async def log(ctx = Depends(get_request_context)):
print(f"來自 {ctx['ip']} 的請(qǐng)求,UA: {ctx['user_agent']}")
return {"message": "Logged"}
優(yōu)點(diǎn):
- 自動(dòng)提取請(qǐng)求相關(guān)數(shù)據(jù)
- 避免在每個(gè)接口中手動(dòng)處理
- 支持結(jié)構(gòu)化日志、追蹤、限流等高級(jí)特性
4. 單元測(cè)試更方便(mock 依賴)
使用依賴注入后,每一個(gè)外部服務(wù)(如數(shù)據(jù)庫(kù)、權(quán)限、上下文)都可以在測(cè)試中 mock 掉,不再依賴真實(shí)服務(wù),非常適合 CI/CD 環(huán)境。
示例:
from fastapi.testclient import TestClient
from main import app
from database import get_db
# Mock 數(shù)據(jù)庫(kù)連接
asyncdefoverride_get_db():
classDummyDB:
asyncdefexecute_query_dict(self, sql):
return [{"id": 1, "username": "test_user"}]
yield DummyDB()
app.dependency_overrides[get_db] = override_get_db
client = TestClient(app)
deftest_get_users():
response = client.get("/users")
assert response.status_code == 200
assert response.json() == [{"id": 1, "username": "test_user"}]
你也可以 override 權(quán)限驗(yàn)證、上下文獲取等依賴項(xiàng):
from auth import verify_token
# mock 權(quán)限校驗(yàn)返回用戶 id
app.dependency_overrides[verify_token] = lambda: 1
優(yōu)點(diǎn):
- 測(cè)試更快,不依賴數(shù)據(jù)庫(kù)
- 可控輸入輸出,斷言更精準(zhǔn)
- 沒有副作用,測(cè)試隔離性強(qiáng)
5. 總結(jié)表格
功能點(diǎn) | 依賴函數(shù) | 作用與優(yōu)點(diǎn) |
數(shù)據(jù)庫(kù)連接 | get_db | 自動(dòng)管理事務(wù),防止資源泄漏,方便測(cè)試 |
權(quán)限校驗(yàn) | verify_token | 校驗(yàn)登錄狀態(tài),可擴(kuò)展為 RBAC |
請(qǐng)求上下文 | get_request_context | 自動(dòng)提取 IP、UA、Headers |
單元測(cè)試替換依賴 | dependency_overrides | 隔離依賴項(xiàng),mock 數(shù)據(jù)源,適用于 CI 測(cè)試場(chǎng)景 |
6. 總結(jié)與建議
FastAPI 的依賴注入系統(tǒng)不僅功能強(qiáng)大,還極其優(yōu)雅。它能幫助你:
- 模塊化業(yè)務(wù)邏輯
- 隔離接口職責(zé)
- 顯著提升可測(cè)試性
- 構(gòu)建高可維護(hù)的大型應(yīng)用
無(wú)論是構(gòu)建微服務(wù)、后臺(tái)管理系統(tǒng),還是機(jī)器學(xué)習(xí)接口服務(wù),推薦都采用 DI + 類型注解的方式構(gòu)建接口和服務(wù)邏輯,優(yōu)雅又實(shí)用。