本文 AI 產出,尚未審核

FastAPI – Query、Path、Body 參數的使用與實務技巧

簡介

在建構 RESTful API 時,如何正確地取得客戶端傳入的資料是每一位開發者必須面對的基本課題。FastAPI 以 型別提示 (type hints) 為核心,將請求參數的驗證與轉換全部交給框架本身,讓開發者只需要專注於業務邏輯。
本單元將深入探討 Query()Path()Body() 三大函式的用法,說明它們在 URL 路徑、查詢字串與請求主體 中的角色,並提供實作範例與最佳實踐,幫助你在專案中快速、正確地處理各種參數。


核心概念

1. 為什麼要使用 Query()Path()Body()

  • 自動驗證:依據型別提示與 pydantic 模型,自動檢查資料是否符合預期。
  • 文件生成:FastAPI 會把參數資訊自動寫入 OpenAPI (Swagger) 文件,前端開發者能即時看到 API 規範。
  • 可讀性:將參數來源明確標註,使程式碼更具表意性,降低維護成本。

:即使不加 Query()Path()Body(),FastAPI 仍會根據參數型別推斷來源,但明確標註能提供更多控制(例如預設值、別名、驗證規則)。


2. Query() – 取得 URL 查詢字串

基本語法

from fastapi import FastAPI, Query

app = FastAPI()

@app.get("/items/")
async def read_items(q: str = Query(default=None, max_length=50)):
    return {"query": q}
  • default:若未提供此參數,使用的預設值。若設為 ... (Ellipsis) 表示必填。
  • max_lengthmin_length:字串長度限制。
  • alias:自訂查詢參數名稱(例如 ?search=...)。

範例 1:分頁參數 + 別名

@app.get("/products/")
async def list_products(
    page: int = Query(1, ge=1, description="目前頁碼"),
    size: int = Query(10, le=100, alias="pageSize", description="每頁筆數")
):
    # 這裡的 size 會從 ?pageSize=... 取得值
    return {"page": page, "size": size}

範例 2:多值查詢 (list)

@app.get("/search/")
async def multi_search(
    tags: list[str] = Query([], description="過濾標籤,支援多個")
):
    # 呼叫方式: /search/?tags=python&tags=fastapi
    return {"tags": tags}

3. Path() – 取得路徑參數

基本語法

from fastapi import Path

@app.get("/users/{user_id}")
async def get_user(user_id: int = Path(..., ge=1)):
    return {"user_id": user_id}
  • ... 表示此參數 必填(路徑參數永遠必填)。
  • gelegtlt 等限制同樣適用於 Path()

範例 3:限定字串格式

@app.get("/orders/{order_id}")
async def read_order(
    order_id: str = Path(..., regex="^ORD-[0-9]{4}$", description="訂單編號,格式 ORD-XXXX")
):
    return {"order_id": order_id}

範例 4:結合 Enum

from enum import Enum

class Region(str, Enum):
    north = "north"
    south = "south"
    east  = "east"
    west  = "west"

@app.get("/region/{region}")
async def get_region(region: Region = Path(...)):
    return {"region": region.value}

4. Body() – 取得請求主體 (JSON、Form、File)

基本語法

from fastapi import Body

@app.post("/items/")
async def create_item(name: str = Body(...), price: float = Body(...)):
    return {"name": name, "price": price}
  • 若參數型別為 pydantic.BaseModel,建議直接使用模型,不必逐一列出 Body()
  • embed=True 可讓單一參數以 JSON 物件包裝,如 {"name": "Apple"}

範例 5:使用 Pydantic Model

from pydantic import BaseModel, Field

class Item(BaseModel):
    name: str = Field(..., max_length=100, description="商品名稱")
    price: float = Field(..., gt=0, description="商品價格")
    tags: list[str] = Field(default_factory=list, description="商品標籤")

@app.post("/items/")
async def create_item(item: Item):
    # FastAPI 會自動把 JSON 轉成 Item 物件
    return {"item_id": 123, "item": item}

範例 6:混合 Body + Query

@app.post("/orders/{user_id}")
async def place_order(
    user_id: int = Path(..., ge=1),
    item: Item = Body(...),
    confirm: bool = Query(False, description="是否直接確認訂單")
):
    # 同時取得路徑、請求體與查詢參數
    status = "confirmed" if confirm else "pending"
    return {"user_id": user_id, "item": item, "status": status}

常見陷阱與最佳實踐

陷阱 說明 解決方式
忘記加 ... Path() 中未使用 ...,導致參數被視為可選,產生 422 錯誤。 必須 使用 Path(... ) 來明確表示必填。
混用 BodyForm 同一個路由同時使用 Body()Form() 會讓 FastAPI 無法決定解析方式。 若需要接收表單,全部改為 Form();若是 JSON,全部改為 Body()
過度使用 Querydefault=None 設為 None 會讓參數變成可選,但若後端邏輯其實必須有值,會產生隱蔽錯誤。 使用 ... 或自行在函式內檢查 None,並回傳 400。
未設定 alias 前端習慣使用駝峰命名,而 Python 使用底線,直接寫 myParam 會導致 422。 Query(..., alias="myParam")Path(..., alias="myParam") 中設定別名。
忽略 OpenAPI 文件 參數說明寫在程式碼中,卻未利用 descriptionexample 等屬性,文件不完整。 為每個參數加上 descriptionexample,提升自動文件品質。

最佳實踐

  1. 盡量使用 Pydantic Model:一次定義所有欄位、驗證規則,保持 API 一致性。
  2. 統一命名風格:路由使用小寫加底線、參數使用 snake_case;若前端需求駝峰,使用 alias 轉換。
  3. 加入範例與說明Field(..., example="Apple")Query(..., description="...") 能讓 Swagger 更友好。
  4. 分層驗證:先在 Path/Query/Body 層面做基礎限制,複雜商業規則則放在服務層或依賴注入。
  5. 測試 422 回應:寫測試確認缺少必填參數、類型不符、驗證失敗時會回傳正確的錯誤資訊。

實際應用場景

場景 參數來源 使用的 FastAPI 工具 範例說明
商品搜尋 多個過濾條件(關鍵字、類別、價格區間) Query()(字串、list、範圍) GET /products?keyword=phone&category=electronics&min_price=100&max_price=500
取得使用者資訊 使用者 ID(路徑) + 權限驗證旗標(查詢) Path() + Query() GET /users/42?include_roles=true
建立訂單 使用者 ID(路徑) + 訂單內容(JSON) + 是否立即付款(查詢) Path() + Body() + Query() POST /orders/42?pay_now=true,Body 為 { "items": [...], "address": "..." }
上傳檔案 檔案本體(Form) + 附加說明(Body) Form() + Body() POST /uploadfile 為 multipart,metadata 為 JSON 字串。
多語系 API 語系代碼(路徑) + 文字內容(Body) Path() + Body() POST /i18n/zh-TW,Body 為 { "key": "welcome", "value": "歡迎使用" }

總結

  • Query()Path()Body() 為 FastAPI 處理不同來源參數的核心工具,藉由型別提示與 Pydantic 驗證,讓 API 的安全性與文件化變得輕而易舉。
  • 明確標註參數來源、設定驗證條件、提供別名與說明,可避免常見的 422 錯誤,提升前端開發者的使用體驗。
  • 在實務開發中,模型化(使用 Pydantic BaseModel)與統一命名是保持代碼可維護性的關鍵;同時,善用 descriptionexamplealias 等屬性,讓自動產生的 OpenAPI 文件真正成為團隊的 API 規範。

掌握這三個函式的細節,你就能在 FastAPI 中快速構建 清晰、可靠且文件完整 的 REST API,為後端服務奠定堅實的基礎。祝開發順利 🚀