這篇文章將教你如何使用 FastAPI 的「依賴注入 (Dependency Injection)」,學會依賴注入後,你不再需要重複複製貼上相同的檢查邏輯,或是手動建立資料庫連線。
什麼是依賴注入 (Dependency Injection)?
依賴注入是一種設計模式,意指「程式運作所需的資源(如資料庫連線、當前使用者),不由函式自己建立,而是由外部框架自動傳遞進來」。這就像去餐廳點餐。你只需要跟服務生說「我要 A 套餐」,廚房(FastAPI)就會自動準備好漢堡、薯條和可樂(依賴項)送到你桌上,你不需要親自走進廚房去煎肉排或裝飲料。
依賴注入基礎概念
1. 定義依賴項 (Dependency)
依賴項本質上只是一個普通的 Python 函式 (Function) 或 類別 (Class)。這個函式負責處理共用的邏輯,例如接收查詢參數或建立資料庫連線。# 這裡定義一個負責處理分頁邏輯的函式
async def common_pagination(skip: int = 0, limit: int = 10):
# 回傳一個字典,包含分頁資訊
return {"skip": skip, "limit": limit}
此函式 common_pagination 獨立於路徑操作之外,定義了預設的分頁參數。
2. 注入依賴 (Depends)
在路徑操作函式中,透過 Depends 關鍵字宣告該函式需要使用上述的共用邏輯。FastAPI 會自動執行依賴函式,並將回傳值指派給參數。
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_pagination(skip: int = 0, limit: int = 10):
return {"skip": skip, "limit": limit}
# 在參數中宣告依賴關係
@app.get("/items/")
async def read_items(pagination: dict = Depends(common_pagination)):
# pagination 變數現在持有 common_pagination 的回傳值
return pagination
當使用者存取 /items/?skip=20 時,FastAPI 會自動解析參數並傳入 common_pagination,再將結果傳給 read_items。
3. 使用 Annotated
使用 typing.Annotated 來標註依賴項,這能讓型別提示 (Type Hints) 更清晰,且便於重複使用。
from fastapi import Depends, FastAPI
from typing import Annotated
app = FastAPI()
async def common_pagination(skip: int = 0, limit: int = 10):
return {"skip": skip, "limit": limit}
# 宣告一個型別別名,將依賴邏輯封裝起來
PaginationDep = Annotated[dict, Depends(common_pagination)]
@app.get("/users/")
async def read_items(pagination: PaginationDep):
return pagination
這種寫法將「參數型別」與「依賴邏輯」結合,提升程式碼可讀性。
依賴注入實作範例
以下範例模擬一個「資料庫連線」的情境,使用 yield 關鍵字可以模擬連線開啟與關閉的生命週期(Context Manager),這是業界處理資料庫 session 的標準寫法。
from typing import Annotated
from fastapi import FastAPI, Depends, HTTPException
app = FastAPI()
# 1. 模擬資料庫連線生成器
async def get_database():
db_connection = "Fake_DB_Connection_Opened"
print("--- 資料庫連線已建立 ---")
try:
yield db_connection # 將連線物件交給路徑函式
finally:
# 當路徑函式執行完畢後,會回頭執行這裡的程式碼
print("--- 資料庫連線已關閉 ---")
# 2. 定義依賴型別
DatabaseDep = Annotated[str, Depends(get_database)]
# 3. 實作 API
@app.get("/users/{user_id}")
async def get_user(user_id: int, db: DatabaseDep):
# 這裡的 db 就是 get_database yield 出來的字串
if user_id == 0:
raise HTTPException(status_code=400, detail="無效的使用者 ID")
return {
"user_id": user_id,
"status": "active",
"db_status": db # 證明依賴已注入
}
當請求進入 /users/1 時,FastAPI 會先執行 get_database 直到 yield,將連線物件傳給 get_user。待 get_user 回傳結果後,FastAPI 會自動執行 finally 區塊內的程式碼,確保資源被正確釋放,防止記憶體洩漏。
常見錯誤與解決方法
- 誤用函式呼叫:在 Depends 中直接呼叫函式(加上括號),導致依賴項只執行一次或行為不符合預期。
- 忽略型別提示:未正確標註型別,導致編輯器無法提供自動補全。
- 全域變數汙染:試圖在全域變數中儲存請求特定的資料。
from fastapi import Depends
async def get_token():
return "fake-token"
# 錯誤寫法
# 不要加括號 (),除非該函式回傳的是一個可呼叫物件 (Callable)
# def route_bad(token = Depends(get_token())): ...
# 正確寫法
# 直接傳遞函式名稱
@app.get(...)
async def route_good(token: str = Depends(get_token)):
print(token)
return {"token": token}
結語
FastAPI 的依賴注入系統能有效解耦程式邏輯,讓資料庫連線、驗證機制與業務邏輯分離,能讓你的程式碼保持乾淨、好維護。記住三個關鍵重點:抽取邏輯(把重複程式碼變成函式)、Depends(使用這個關鍵字注入)、自動解析參數傳遞(FastAPI 會幫你處理參數傳遞)。











