FastAPI Request 路徑參數驗證 (Path parameters validation)
就像 Query 用於驗證查詢參數,FastAPI 提供了 Path 類別來驗證路徑參數。
導入 Path
from typing import Optional
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: int = Path(..., title="The ID of the item to get"),
q: Optional[str] = Query(None, alias="item-query"),
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
使用 Annotated (推薦)
在現代 FastAPI 中,建議使用 typing.Annotated 來讓程式碼更清晰且更符合 Python 型別標準:
from typing import Annotated, Optional
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get", ge=1)],
q: Annotated[Optional[str], Query(alias="item-query")] = None,
):
return {"item_id": item_id, "q": q}
路徑參數原本就是必填的 (因為它是 URL 的一部分),所以即使你用了
Path,你還是應該將預設值設為 ... (Ellipsis),雖然設為 None 在語法上沒錯,但實務上沒有意義(因為不會有路徑參數是空的情況,除非路徑匹配規則改變)。不過為了保持一致性,建議習慣寫 Path(...)。數值驗證:大於、小於
對於數值型別 (int, float) 的參數,Path 和 Query 都支援以下驗證參數:
gt:大於 (greater than)>ge:大於等於 (greater than or equal)>=lt:小於 (less than)<le:小於等於 (less than or equal)<=
範例:必須大於等於 1
@app.get("/items/{item_id}")
async def read_items(
item_id: int = Path(..., title="The ID of the item to get", ge=1),
q: str
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
如果你請求 /items/0,會得到 422 錯誤,因為 0 不符合 ge=1。
範例:範圍限制
假設你要限制 item_id 必須在 1 到 1000 之間。
@app.get("/items/{item_id}")
async def read_items(
item_id: int = Path(..., title="The ID of the item to get", gt=0, le=1000),
q: str,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
浮點數、大於和小於
這些驗證規則同樣適用於 float。
@app.get("/items/{item_id}")
async def read_items(
item_id: int = Path(..., title="The ID of the item to get", ge=1),
q: str,
size: float = Query(..., gt=0, lt=10.5)
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
參數排序的注意事項
如果你使用了 Path 和 Query,並且將參數設為有預設值的選填參數,你可能會遇到 Python 語法限制:「非預設值參數不能放在有預設值參數之後」。
例如:
# 這是錯誤的寫法 (Python Syntax Error)
async def read_items(
q: str = Query(None), # 有賦值 (Default)
item_id: int # 沒賦值 (Non-default),不能放後面
):
pass
但在 FastAPI 中,為了讓這種情況合法並且能用,你可以將 * 作為函數的第一個參數。這告訴 Python 之後的所有參數都必須以「關鍵字參數 (Keyword Arguments)」的方式傳入 (即 key=value)。
不過,對於 FastAPI 的路徑操作函數來說,這問題通常較少見,因為 item_id 這種路徑參數通常會放在前面。但如果你一定要把 q 放前面,可以這樣寫:
async def read_items(
*,
q: str = Query(None),
item_id: int,
size: float = Query(..., gt=0, lt=10.5)
):
pass
這在 Python 3.10+ 或使用了 Pydantic v2 後可能有不同的行為細節,但通常如果你遇到 SyntaxError: non-default argument follows default argument,加上 * 通常是解法。
總結
- 使用
Path對路徑參數進行額外驗證。 - 數值驗證參數:
gt,ge,lt,le。 - 這些驗證參數通用于
Path和Query。