本文 AI 產出,尚未審核

FastAPI 教學 – 路由(Routing)

主題:路由參數(Path parameters)


簡介

FastAPI 中,路由(Route)是 API 與外部世界溝通的入口,而 路由參數(Path parameters)則是讓同一條路由能根據不同的「路徑變數」執行不同的邏輯。
不論是取得單筆商品資料、編輯特定使用者或是刪除某筆記錄,都會需要把 資源的唯一識別碼(如 idslug)以路徑參數的形式帶入。

掌握路由參數的寫法與驗證機制,不僅能讓 API 語意更清晰,還能利用 FastAPI 內建的型別檢查與自動文件產生,大幅提升開發效率與可維護性。本文將從概念說明、實作範例、常見陷阱到最佳實踐,完整介紹如何在 FastAPI 中使用路由參數。


核心概念

1. 基本語法

在 FastAPI 中,路由參數是以大括號 {} 包住的路徑片段,並且可以直接在路由函式的參數列表中聲明對應的變數名稱與型別:

from fastapi import FastAPI

app = FastAPI()

@app.get("/users/{user_id}")
async def read_user(user_id: int):
    """
    取得單一使用者資料
    - `user_id` 會自動被 FastAPI 轉換成 int
    - 若傳入非整數,會回傳 422 錯誤
    """
    return {"user_id": user_id, "name": f"User{user_id}"}
  • {user_id}:路徑參數的名稱。
  • user_id: int:在函式參數上加上型別註解,FastAPI 會自動完成 型別轉換驗證

重點:只要路徑參數名稱與函式參數名稱相同,即可自動對應;若名稱不一致,則需要使用 Path 物件手動映射。


2. 使用 Path 進階設定

Path 允許我們為參數設定 預設值、驗證規則、說明文字,這些資訊會直接反映在自動產生的 OpenAPI 文件中。

from fastapi import FastAPI, Path

app = FastAPI()

@app.get("/items/{item_id}")
async def read_item(
    item_id: int = Path(..., title="商品 ID", gt=0, description="必須是正整數")
):
    """
    取得商品資訊
    - `gt=0` 代表只能接受大於 0 的數字
    - `...` 表示此參數為必填
    """
    return {"item_id": item_id, "price": 199}
  • titledescription:文件說明。
  • gtltgele:數值範圍限制。
  • regex:字串符合正則表達式。

3. 多個路由參數

同一條路由可以同時接受多個參數,順序與名稱皆依路徑定義而定。

@app.get("/users/{user_id}/orders/{order_id}")
async def read_user_order(user_id: int, order_id: str):
    """
    取得特定使用者的特定訂單
    - `user_id` 為整數
    - `order_id` 為字串,可自行加入 regex 驗證
    """
    return {"user_id": user_id, "order_id": order_id}

4. 參數型別的多樣性

FastAPI 支援多種型別,包括 intfloatbooldatetimeUUID 等。以下示範 datetimeUUID 的使用:

from datetime import datetime
from uuid import UUID

@app.get("/events/{event_date}")
async def read_event(event_date: datetime):
    """
    取得特定日期的活動資訊
    - 需要符合 ISO 8601 格式,例如 2023-09-01T10:00:00
    """
    return {"event_date": event_date.isoformat()}

@app.get("/files/{file_id}")
async def read_file(file_id: UUID):
    """
    以 UUID 取得檔案資訊
    """
    return {"file_id": str(file_id)}

FastAPI 會自動把字串轉換成對應的 Python 物件,若格式不符則回傳 422 Unprocessable Entity


5. 路徑參數與查詢參數的差異

類型 定義位置 用途 範例
路徑參數 URL 路徑 (/users/{id}) 標示資源唯一識別碼,必填 /users/123
查詢參數 URL 查詢字串 (?page=2) 用於過濾、分頁、排序等 可選 條件 /users?page=2

技巧:當參數是 資源的唯一鍵 時,請使用路徑參數;若是 過濾條件,則使用查詢參數。


程式碼範例(實用範例 5 個)

範例 1:簡易的 CRUD – 取得單筆資料

@app.get("/books/{book_id}")
async def get_book(book_id: int = Path(..., gt=0)):
    """
    取得指定書本的資訊
    """
    # 假設有一個資料庫查詢函式
    book = {"id": book_id, "title": f"Book {book_id}"}
    return book

範例 2:使用正則驗證的字串參數

@app.get("/users/{username}")
async def get_user(
    username: str = Path(..., regex="^[a-zA-Z0-9_]{3,20}$", title="使用者名稱")
):
    """
    僅接受英數與底線,長度 3~20 的使用者名稱
    """
    return {"username": username}

範例 3:多參數與型別混合

@app.get("/orders/{order_id}/items/{item_id}")
async def get_order_item(
    order_id: UUID,
    item_id: int = Path(..., ge=1, description="商品編號,必須大於等於 1")
):
    """
    依照訂單 UUID 與商品編號取得明細
    """
    return {"order_id": str(order_id), "item_id": item_id}

範例 4:日期時間參數 + 查詢參數結合

from fastapi import Query
from datetime import date

@app.get("/reports/{report_date}")
async def get_report(
    report_date: date,
    include_details: bool = Query(False, description="是否包含詳細資料")
):
    """
    取得特定日期的報表,`include_details` 為可選的查詢參數
    """
    report = {"date": report_date.isoformat(), "summary": "簡要報表"}
    if include_details:
        report["details"] = "這裡是詳細資料"
    return report

範例 5:自訂路徑參數類別(使用 Pydantic)

from pydantic import BaseModel, conint

class PageInfo(BaseModel):
    page: conint(ge=1) = 1          # 必須 >= 1
    size: conint(gt=0, le=100) = 10 # 1~100

@app.get("/products/{category}/page")
async def list_products(category: str, info: PageInfo = Depends()):
    """
    分頁列出某類別的商品,使用 Pydantic 進行驗證
    """
    return {
        "category": category,
        "page": info.page,
        "size": info.size,
        "items": []  # 假資料
    }

常見陷阱與最佳實踐

陷阱 說明 解決方式
路徑參數未宣告型別 預設會當成 str,但容易在後續運算時出現型別錯誤。 明確寫出型別intUUID 等),讓 FastAPI 自動驗證。
參數名稱不一致 路徑 {user_id} 與函式參數 uid 不同,會導致 404。 使用 Path(..., alias="user_id") 或保持名稱一致。
過寬的路由衝突 兩條路由如 /items/{id}/items/latest 會產生衝突。 把固定路由放在前面,或使用更精確的正則限制。
未處理 422 錯誤 使用者傳入不合法的參數會直接回 422,若未捕捉會讓前端不易除錯。 使用 Exception Handlers 統一格式化錯誤回應。
大量路徑參數導致 URL 雜亂 超過 3~4 個參數會影響可讀性與維護。 考慮改用 查詢參數請求主體(body)

最佳實踐

  1. 盡量使用型別註解:讓 FastAPI 自動完成轉換與驗證。
  2. 為每個參數加上說明 (titledescription):有助於自動文件的可讀性。
  3. 使用 Path 的驗證條件gtltregex)代替手寫檢查。
  4. 保持路由的語意清晰:資源層級使用 /resource/{id},操作(如 activate)則放在子路徑或使用 HTTP 方法。
  5. 統一錯誤回應格式:搭配 HTTPException 或自訂的 ExceptionHandler,提供前端友好的錯誤訊息。

實際應用場景

場景 為何使用路徑參數 範例路由
電商系統的商品細節 商品編號是唯一鍵,適合放在路徑中。 /products/{product_id}
社群平台的使用者檔案 使用者名稱或 UUID 為資源標識。 /users/{username}/users/{user_id}
多租戶 SaaS 租戶代碼是必須的前置條件。 /tenants/{tenant_id}/reports/{year}
文件下載服務 檔案的 UUID 或 hash 必須直接映射。 /files/{file_hash}
時間序列資料查詢 日期或時間戳記作為路徑參數,語意更直觀。 /metrics/{date}

在上述情況下,使用路徑參數不僅讓 API URL 結構更具可讀性,也能利用 FastAPI 的 自動驗證 減少手動錯誤檢查,提升開發與除錯效率。


總結

  • 路由參數是 FastAPI 中最基礎且最常用的功能之一,透過大括號 {} 定義、型別註解與 Path 物件的進階設定,我們可以快速建立 型別安全文件完整的 API。
  • 充分利用 數值/字串驗證、正則表達式、UUID、datetime 等內建型別,可讓 API 在收到不合法請求時即時回 422,減少後端的防呆程式碼。
  • 在設計路由時應遵守 語意清晰、層級分明 的原則,避免過多路徑參數或路由衝突,並搭配 例外處理 讓錯誤訊息更友善。

掌握這些概念與實作技巧後,你就能在 FastAPI 專案中自如地使用路由參數,打造 高可讀、易維護、功能完整 的 RESTful API。祝開發順利! 🚀