FastAPI 路由教學 – 動態路由(路由參數轉換器)
簡介
在 Web API 開發中,路由(Routing) 是連結 HTTP 請求與程式碼的橋樑。FastAPI 以宣告式的方式定義路由,讓開發者可以快速建立 RESTful 介面。而在實務上,絕大多數的 API 需要根據 動態參數(例如使用者 ID、日期、檔案名稱)來返回不同的結果,這時就會用到 路由參數轉換器(Path Parameter Converters)。
路由參數轉換器不僅能自動將 URL 中的字串轉型為 Python 型別,還能在錯誤發生時提前拋出 422 Unprocessable Entity,讓 API 更安全、更易於除錯。掌握這項技巧,能讓你的 FastAPI 專案在 可讀性、效能與維護性 上都有顯著提升。
核心概念
1. 基本的動態路由
FastAPI 允許在路徑字串中使用大括號 {} 包住參數名稱,形成「動態路由」:
from fastapi import FastAPI
app = FastAPI()
@app.get("/users/{user_id}")
async def read_user(user_id: int):
"""
取得單一使用者資料
- user_id 會自動被轉換成 int
- 若轉換失敗,FastAPI 會回傳 422
"""
return {"user_id": user_id}
關鍵點:
user_id: int會告訴 FastAPI 將 URL 中的字串轉成int,若傳入非整數則直接回 422。- 路由函式本身是 非同步(
async)的,能配合await呼叫 I/O 密集型操作。
2. 常見的內建型別轉換器
FastAPI 內建以下常見的型別轉換器,使用時只要在函式參數加上對應的型別註解即可:
| 型別 | 範例路由 | 轉換說明 |
|---|---|---|
int |
/items/{item_id} |
轉成整數,負數也允許 |
float |
/price/{value} |
轉成浮點數 |
bool |
/flags/{active} |
"true"/"false"、"1"/"0" |
str |
/search/{keyword} |
預設為字串,支援 URL 編碼 |
path |
/files/{file_path:path} |
捕捉 多層路徑(含 /) |
範例:使用 path 捕捉子路徑
@app.get("/static/{file_path:path}")
async def read_static(file_path: str):
"""
讀取任意深度的靜態檔案路徑
- file_path 會保留斜線,例如 "css/main.css"
"""
return {"file_path": file_path}
Tip:
path轉換器只能放在路由的最後一段,否則會產生路由匹配衝突。
3. 自訂型別轉換器(自訂 Path Converter)
有時候內建的型別不夠用,例如需要驗證 UUID、日期、或是 正則表達式。FastAPI 允許你 自訂型別,只要符合 Pydantic 的驗證模型或是實作 __get_validators__ 方法即可。
範例:自訂 ItemCode(只能是三位大寫英文字母 + 四位數字)
import re
from typing import Any
from fastapi import FastAPI, HTTPException
class ItemCode(str):
regex = re.compile(r"^[A-Z]{3}\d{4}$")
@classmethod
def __get_validators__(cls):
yield cls.validate
@classmethod
def validate(cls, v: Any):
if not isinstance(v, str):
raise TypeError("字串類型才有效")
if not cls.regex.match(v):
raise ValueError("ItemCode 必須符合 AAA9999 格式")
return v
app = FastAPI()
@app.get("/items/{code}")
async def get_item_by_code(code: ItemCode):
"""
只接受符合規則的 ItemCode
- 若不符合,回傳 422 並顯示錯誤訊息
"""
return {"code": code}
重點:自訂型別必須提供
__get_validators__產生驗證函式,FastAPI 會在路由匹配時自動執行。
4. 多參數組合與優先順序
路由的匹配順序遵循 先定義先匹配 的原則。若有多條路由可能同時符合,FastAPI 會挑選「最具體」的那一條。以下示範同時使用 int 與 str,以及 path:
@app.get("/products/{product_id}")
async def get_product_by_id(product_id: int):
return {"type": "id", "product_id": product_id}
@app.get("/products/{slug}")
async def get_product_by_slug(slug: str):
return {"type": "slug", "slug": slug}
- 請注意:
int會比str更具體,所以/products/123會走第一條路由;/products/awesome-widget走第二條。 - 為避免衝突,建議將類型較寬鬆的路由放在最後。
5. 參數驗證與回傳錯誤
FastAPI 結合 Pydantic,會在參數驗證失敗時自動回傳 422,錯誤訊息會列出哪個參數、期望型別與實際收到的值。例如:
GET /users/not-an-int
回應:
{
"detail": [
{
"loc": ["path", "user_id"],
"msg": "value is not a valid integer",
"type": "type_error.integer"
}
]
}
開發者只需要關注 正確的型別註解,其餘驗證與錯誤處理都交給 FastAPI 完成。
常見陷阱與最佳實踐
| 陷阱 | 說明 | 解法 / 最佳實踐 |
|---|---|---|
| 路由衝突 | 多條路由同時匹配導致不易預測的行為。 | 使用 更具體的型別(int > float > str),或將寬鬆路由放在最後。 |
path 位置錯誤 |
path 只能放在路由最後,否則會捕捉過多字元。 |
確保 path 參數是 最後一段,並盡量加上前綴(如 /files/{file_path:path})。 |
自訂驗證忘記 __get_validators__ |
自訂類別不會被 FastAPI 呼叫,導致驗證失效。 | 必須實作 __get_validators__ 並在其中 yield 驗證函式。 |
| 過度依賴路由參數驗證 | 把所有邏輯都寫在路由參數上,難以重用。 | 只在路由層做型別與簡易驗證,業務邏輯放在 service / repository 層。 |
未使用 Enum 取代硬編碼字串 |
直接在路由參數使用字串,易造成拼寫錯誤。 | 使用 Enum 定義允許值,FastAPI 會自動驗證。 |
範例:使用 Enum 作為路由參數
from enum import Enum
from fastapi import FastAPI
class Color(str, Enum):
red = "red"
green = "green"
blue = "blue"
app = FastAPI()
@app.get("/colors/{color}")
async def get_color(color: Color):
"""
只接受三種顏色,若傳入其他字串會回 422
"""
return {"selected_color": color.value}
實際應用場景
電商商品查詢
/products/{product_id:int}直接以商品編號查詢。/products/{slug:str}允許 SEO 友好的網址。/categories/{category_path:path}支援多層分類,如electronics/phones/smartphones。
檔案服務 (File Service)
/files/{file_path:path}用於下載或預覽任意深度的檔案。- 搭配
aiofiles非同步讀寫,提高 I/O 效能。
使用者驗證與授權
/users/{user_id:int}/orders/{order_id:int}同時驗證兩層資源的關聯性。- 若需要 UUID,使用
uuid.UUID型別或自訂UUID4驗證。
時間序列資料
/metrics/{date:date}(需要自訂date轉換器)或直接使用datetime.date。- 確保日期格式正確,避免因字串解析錯誤導致資料錯位。
多語系或地區化
/api/{lang:str}/{resource}讓lang只接受en,zh-tw,ja等 Enum,確保語系一致。
總結
- 動態路由 是 FastAPI 建立彈性 API 的基礎,透過 路由參數轉換器 能在請求階段即完成型別轉換與驗證,減少手動檢查的負擔。
- 內建的
int,float,bool,str,path已能覆蓋大多數需求;若有特殊規則,自訂型別 與 Enum 提供了強大的擴充能力。 - 設計路由時應注意路由衝突與匹配順序,將寬鬆的路由放在最後,並盡可能使用具體型別提升可讀性與性能。
- 在實務專案中,將 驗證責任限定在路由層,其餘業務邏輯交給服務層或資料層,才能保持程式碼的可維護性與可測試性。
掌握了動態路由與參數轉換器之後,你的 FastAPI 應用將會更安全、簡潔且易於擴充。快把這些技巧帶回你的專案,讓 API 開發變得更順手吧!