FastAPI – Query String 自動解析
簡介
在 Web API 的設計中,Query String 是最常見的參數傳遞方式之一。相較於路徑參數(Path)或請求主體(Body),Query String 允許使用者在 URL 後面以 ?key=value&... 的形式直接提供過濾條件、分頁資訊、排序方式等。
FastAPI 以 Pydantic 為基礎,提供了「自動解析」的功能:只要在路由函式的參數上加上型別註解,框架就會自動把傳入的 query string 轉換成相對應的 Python 資料型別,甚至可以自動驗證、轉換與預設值。
本篇文章將深入探討 FastAPI 如何處理 query string,從基本用法到進階技巧,並提供實務範例與最佳實踐,協助你在開發 API 時寫出 乾淨、可維護且安全 的程式碼。
核心概念
1. 基本的 query 參數自動解析
FastAPI 只要在路由函式的參數前加上型別註解,就會把同名的 query string 取出並轉型。例如:
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/")
def read_items(q: str = None):
"""
q: 從 query string 取得的字串,若未提供則為 None
"""
return {"query": q}
- 呼叫
GET /items/?q=fastapi→ 回傳{"query":"fastapi"} - 若未帶
q,則回傳{"query":null}
重點:不需要額外的 request.query_params,FastAPI 已經幫你完成解析。
2. 多種資料型別的自動轉換
| Python 型別 | 範例 query string | 轉換結果 |
|---|---|---|
int |
?page=2 |
page = 2 (int) |
float |
?price=9.99 |
price = 9.99 (float) |
bool |
?active=true |
active = True |
list[int] |
?ids=1&ids=2&ids=3 |
ids = [1,2,3] |
datetime |
?date=2023-01-01 |
date = datetime(2023,1,1) |
範例 1:分頁與排序
from fastapi import FastAPI, Query
from typing import List, Optional
app = FastAPI()
@app.get("/products/")
def list_products(
page: int = Query(1, ge=1, description="目前頁碼,最小值 1"),
size: int = Query(20, le=100, description="每頁筆數,最大 100"),
sort: Optional[List[str]] = Query(
None,
description="排序欄位,支援多個,例如 sort=price&sort=name"
)
):
"""
FastAPI 會自動把 `page`、`size` 轉成 int,`sort` 轉成 List[str]。
若 query 不存在,會使用預設值。
"""
return {
"page": page,
"size": size,
"sort": sort or []
}
GET /products/?page=3&size=50&sort=price&sort=name
→{"page":3,"size":50,"sort":["price","name"]}
3. 使用 Query 物件自訂驗證與說明
fastapi.Query 讓你在參數上加上 驗證規則、預設值、描述文字,這些資訊會自動呈現在 OpenAPI 文件中。
範例 2:日期範圍過濾
from fastapi import FastAPI, Query
from datetime import datetime
from typing import Optional
app = FastAPI()
@app.get("/orders/")
def filter_orders(
start: Optional[datetime] = Query(
None,
description="起始日期,格式 YYYY-MM-DD",
example="2023-01-01"
),
end: Optional[datetime] = Query(
None,
description="結束日期,格式 YYYY-MM-DD",
example="2023-01-31"
)
):
"""
若提供 start / end,FastAPI 會自動把字串轉成 datetime。
若格式不符合,會回傳 422 錯誤。
"""
return {"start": start, "end": end}
- 正確呼叫:
GET /orders/?start=2023-01-01&end=2023-01-31 - 錯誤格式:
GET /orders/?start=20230101→ 422 Validation Error
4. 解析嵌套結構:使用 Pydantic Model
當 query 需要更複雜的結構時,可以把 Pydantic Model 當作 query 參數的型別,FastAPI 會逐層解析。
範例 3:搜尋條件模型
from fastapi import FastAPI, Depends
from pydantic import BaseModel, Field
from typing import List, Optional
app = FastAPI()
class SearchFilter(BaseModel):
keyword: Optional[str] = Field(None, description="搜尋關鍵字")
categories: Optional[List[int]] = Field(
None, description="分類 ID 列表,例: categories=1&categories=2"
)
price_min: Optional[float] = Field(
None, ge=0, description="最低價格"
)
price_max: Optional[float] = Field(
None, gt=0, description="最高價格"
)
def get_filter(
keyword: Optional[str] = None,
categories: Optional[List[int]] = None,
price_min: Optional[float] = None,
price_max: Optional[float] = None,
) -> SearchFilter:
return SearchFilter(
keyword=keyword,
categories=categories,
price_min=price_min,
price_max=price_max,
)
@app.get("/search/")
def search_items(filter: SearchFilter = Depends(get_filter)):
"""
透過 Depends + Pydantic Model,將多個 query 參數彙整成一個物件。
這樣的寫法在大型 API 中非常好維護。
"""
return {"filter": filter.dict()}
- 呼叫
GET /search/?keyword=phone&categories=1&categories=3&price_min=100
→{"filter":{"keyword":"phone","categories":[1,3],"price_min":100.0,"price_max":null}}
5. 多值參數與陣列的處理
FastAPI 預設支援「重複鍵」的 query string,會自動產生 list。若想接受逗號分隔的字串,也可以自行寫 依賴函式 轉換。
範例 4:逗號分隔的 ID 列表
from fastapi import FastAPI, Query, Depends
from typing import List
app = FastAPI()
def csv_to_list(csv: str = Query(None)):
"""把逗號分隔的字串轉成 List[int],若為 None 則回傳空列表"""
if not csv:
return []
return [int(i) for i in csv.split(",")]
@app.get("/batch/")
def batch_process(ids: List[int] = Depends(csv_to_list)):
"""
使用 Depends 把 `ids=1,2,3` 轉成 [1,2,3]。
同時也支援 `ids=1&ids=2&ids=3` 的寫法。
"""
return {"ids": ids}
GET /batch/?ids=10,20,30→{"ids":[10,20,30]}GET /batch/?ids=10&ids=20&ids=30→{"ids":[10,20,30]}
常見陷阱與最佳實踐
| 陷阱 | 說明 | 解法 |
|---|---|---|
| 忘記加型別註解 | FastAPI 會把參數視為 path 而非 query,導致 404 或 422。 | 確保每個 query 參數都有明確的型別(str、int、bool…)。 |
| 布林值的字串 | ?flag=0、?flag=false 皆會被解析為 False,但 ?flag=any 會拋出錯誤。 |
使用 `Query(..., regex="^(true |
| 列表的預設值 | ids: List[int] = [] 會在每次請求時共用同一個列表(Python 的可變預設值問題)。 |
使用 ids: List[int] = Query(None),然後在函式內處理 None 為空列表。 |
| 日期格式不一致 | FastAPI 僅支援 ISO 8601(YYYY-MM-DD),若前端傳 DD/MM/YYYY 會失敗。 |
在前端統一格式或自訂 datetime 解析器(使用 pydantic 的 validator)。 |
| 過多 query 參數 | 大量參數會讓 OpenAPI 文件難以閱讀,且易產生維護問題。 | 使用 Pydantic Model + Depends 把相關參數彙整,保持路由簽名簡潔。 |
最佳實踐:
- 盡可能使用
Query物件,把驗證、說明、範例一次寫好。 - 將相關參數抽象成 Model,搭配
Depends,讓程式碼更具可讀性。 - 避免在 URL 中傳遞大量資料,若資料量大或結構複雜,改用 POST + Body。
- 統一錯誤訊息:利用
HTTPException或自訂的RequestValidationError處理器,提供前端友善的回應。
實際應用場景
1. 電子商務平台的商品搜尋
使用者可以在 URL 中指定 category, price_min, price_max, sort, page, size 等多個條件。透過 Pydantic Model + Depends,我們只需要寫一次驗證邏輯,且自動產生的 Swagger 文件會清楚列出每個參數的說明與範例。
2. 後台管理系統的報表產出
報表往往需要 日期範圍、多值過濾(如多個部門 ID)以及 匯出格式(CSV、PDF)。結合 datetime、List[int]、Enum,FastAPI 能在收到錯誤參數時即回傳 422,減少後端額外的防呆程式。
3. 移動端 API 的分頁機制
行動裝置頻寬有限,必須使用 輕量的 GET 並配合 page、limit、cursor 等參數。FastAPI 的自動轉型讓開發者只需要關注商業邏輯,無需手動解析字串或做型別轉換。
總結
- FastAPI 透過型別註解與
Query物件,提供了即時、可靠的 query string 解析,不僅省下手寫解析程式碼的時間,也自動產生完整的 OpenAPI 文件。 - 從 基本型別(
int,bool)到 複雜結構(List,datetime, Pydantic Model),只要正確宣告,框架會自動完成驗證與轉換。 - 為了避免常見陷阱,建議 使用
Query來設定預設值、驗證規則與說明,以及 把相關參數抽象成 Model + Depends,提升可讀性與維護性。 - 在實務開發中,適當利用 query string 進行 篩選、分頁、排序,能讓 API 更符合前端需求,同時保持高效能與易測試性。
掌握了 FastAPI 的 query string 自動解析後,你就能快速構建 乾淨、可擴充且具備完整文件 的 RESTful API,為後續的功能開發與團隊協作奠定堅實基礎。祝你開發順利!