測驗:FastAPI 路由與參數處理
共 5 題,點選答案後會立即顯示結果
1. 在 FastAPI 中,下列哪種參數會從網址路徑中取得?
@app.get(“/users/{user_id}”)
def get_user(user_id: int):
return {“user_id”: user_id}
2. 當訪問 /items?skip=5&limit=20 時,下列哪個函式定義可以正確接收這些參數?
3. 在 FastAPI 中,如何讓一個參數變成「必填」?
4. 下列程式碼中,Path(ge=1) 的作用是什麼?
@app.get(“/users/{user_id}”)
def get_user(user_id: int = Path(ge=1)):
return {“user_id”: user_id}
5. 在下列函式中,FastAPI 如何判斷 user_id 和 skip 分別是什麼類型的參數?
@app.get(“/users/{user_id}/items”)
def get_user_items(user_id: int, skip: int = 0):
…
一句話說明
讓 API 能接收動態網址和查詢條件,自動驗證格式。
這篇要學什麼
看完這篇,你會看懂:
/users/{user_id}這種動態路由在幹嘛?skip=0&limit=10這種查詢參數怎麼處理- FastAPI 怎麼自動檢查參數格式
Path 參數:動態路由
最小範例
from fastapi import FastAPI
app = FastAPI()
@app.get("/users/{user_id}")
def get_user(user_id: int):
return {"user_id": user_id}
Code language: JavaScript (javascript)逐行翻譯
@app.get("/users/{user_id}") # 當訪問 /users/123 時執行
def get_user(user_id: int): # user_id 會是 123,自動轉成整數
return {"user_id": user_id}
Code language: PHP (php)這在幹嘛
{user_id} 是佔位符,會自動對應到函式參數:
| 訪問網址 | user_id 的值 |
|---|---|
/users/1 |
1 |
/users/100 |
100 |
/users/abc |
錯誤(不是整數) |
翻譯:「用戶訪問 /users/任意數字,我就把那個數字抓出來用」
Query 參數:查詢字串
最小範例
@app.get("/items")
def get_items(skip: int = 0, limit: int = 10):
return {"skip": skip, "limit": limit}
Code language: JavaScript (javascript)逐行翻譯
@app.get("/items") # 固定路徑,沒有 {}
def get_items(skip: int = 0, limit: int = 10): # 不在路徑裡的參數 = Query 參數
return {"skip": skip, "limit": limit}
Code language: PHP (php)這在幹嘛
不在路徑裡的參數,會從 ? 後面抓:
| 訪問網址 | skip | limit |
|---|---|---|
/items |
0 |
10 |
/items?skip=5 |
5 |
10 |
/items?skip=5&limit=20 |
5 |
20 |
翻譯:「用戶可以用 ?skip=5&limit=20 指定要跳過幾筆、取幾筆」
Path vs Query:怎麼分辨
FastAPI 自動判斷:
@app.get("/users/{user_id}/items")
def get_user_items(user_id: int, skip: int = 0):
...
Code language: JavaScript (javascript)| 參數 | 類型 | 原因 |
|---|---|---|
user_id |
Path | 出現在路徑 {user_id} 裡 |
skip |
Query | 沒出現在路徑裡 |
訪問方式:/users/123/items?skip=10
必填 vs 可選參數
規則很簡單
def get_items(
name: str, # 必填(沒有預設值)
skip: int = 0, # 可選(有預設值)
limit: int = 10 # 可選(有預設值)
):
Code language: PHP (php)| 有預設值 | 結果 |
|---|---|
| 沒有 | 必填,不帶就報錯 |
| 有 | 可選,不帶就用預設值 |
範例
@app.get("/search")
def search(q: str, page: int = 1):
return {"q": q, "page": page}
Code language: JavaScript (javascript)| 訪問 | 結果 |
|---|---|
/search |
錯誤:缺少 q |
/search?q=hello |
OK:q=”hello”, page=1 |
/search?q=hello&page=3 |
OK:q=”hello”, page=3 |
Optional:明確標示可選
最小範例
from typing import Optional
@app.get("/items")
def get_items(name: Optional[str] = None):
return {"name": name}
Code language: JavaScript (javascript)這在幹嘛
Optional[str] = None 表示:
- 可以不傳(None)
- 傳的話必須是字串
翻譯:「name 可以不給,給的話要是文字」
Python 3.10+ 寫法
def get_items(name: str | None = None): # 跟 Optional[str] 一樣
...
Code language: PHP (php)Path() 和 Query():進階驗證
當你需要更嚴格的檢查時用。
Path() 範例
from fastapi import Path
@app.get("/users/{user_id}")
def get_user(user_id: int = Path(ge=1)): # ge = greater or equal,大於等於 1
return {"user_id": user_id}
Code language: PHP (php)| 訪問 | 結果 |
|---|---|
/users/1 |
OK |
/users/0 |
錯誤:必須 >= 1 |
/users/-5 |
錯誤:必須 >= 1 |
Query() 範例
from fastapi import Query
@app.get("/items")
def get_items(
skip: int = Query(default=0, ge=0), # 最小 0
limit: int = Query(default=10, le=100) # 最大 100
):
return {"skip": skip, "limit": limit}
Code language: PHP (php)常用驗證參數
| 參數 | 意思 | 範例 |
|---|---|---|
ge |
大於等於 | ge=0 → 最小 0 |
le |
小於等於 | le=100 → 最大 100 |
gt |
大於 | gt=0 → 必須 > 0 |
lt |
小於 | lt=100 → 必須 < 100 |
min_length |
最短長度 | min_length=1 → 至少 1 字元 |
max_length |
最長長度 | max_length=50 → 最多 50 字元 |
字串長度驗證
@app.get("/search")
def search(q: str = Query(min_length=1, max_length=50)):
return {"q": q}
Code language: JavaScript (javascript)翻譯:「搜尋關鍵字至少 1 個字,最多 50 個字」
AI 最常這樣用
用法 1:RESTful 資源路由
@app.get("/users/{user_id}") # 取得單一用戶
@app.get("/users/{user_id}/posts") # 取得用戶的文章
@app.delete("/posts/{post_id}") # 刪除單一文章
Code language: PHP (php)用法 2:分頁查詢
@app.get("/posts")
def get_posts(skip: int = 0, limit: int = 10):
return db.query(Post).offset(skip).limit(limit).all()
Code language: CSS (css)用法 3:篩選搜尋
@app.get("/products")
def get_products(
category: Optional[str] = None,
min_price: Optional[float] = None,
max_price: Optional[float] = None
):
...
Code language: CSS (css)Vibe Coder 檢查點
看到路由和參數時確認:
- [ ]
{xxx}在路徑裡 → Path 參數,會自動帶入 - [ ] 參數有預設值 → 可選;沒預設值 → 必填
- [ ] 參數有型別標註 → FastAPI 自動驗證格式
- [ ] 用了
Path()或Query()→ 有額外的驗證規則
常見錯誤對照
| 錯誤訊息 | 原因 | 解法 |
|---|---|---|
value is not a valid integer |
傳了非整數給 int 參數 | 檢查傳的值 |
field required |
必填參數沒給 | 補上參數或加預設值 |
ensure this value is greater than or equal to X |
違反 ge 限制 | 傳符合範圍的值 |
ensure this value has at least X characters |
違反 min_length | 傳更長的字串 |
小結
| 概念 | 寫法 | 翻譯 |
|---|---|---|
| Path 參數 | /{user_id} |
從網址路徑抓值 |
| Query 參數 | ?skip=0 |
從問號後面抓值 |
| 必填 | name: str |
不給就報錯 |
| 可選 | name: str = None |
不給就用預設值 |
| 進階驗證 | Path(ge=1) |
額外檢查範圍/長度 |
下一篇我們會學習如何用 Pydantic 定義請求和回應的資料結構。
進階測驗:FastAPI 路由與參數處理
測驗目標:驗證你是否能在實際情境中應用所學。
共 5 題,包含情境題與錯誤診斷題。
共 5 題,包含情境題與錯誤診斷題。
1. 你正在開發一個電商 API,需要實作「取得單一商品」的端點。商品 ID 是正整數,不能為 0 或負數。哪個實作方式最符合需求? 情境題
2. 你需要實作一個搜尋 API,需求如下:關鍵字 (q) 是必填、頁碼 (page) 預設為 1、每頁筆數 (limit) 預設為 10 且最大 100。哪個實作最正確? 情境題
3. 你正在開發部落格 API,需要取得某個用戶的所有文章,並支援分頁。網址格式應該是 /users/123/posts?skip=0&limit=10。哪個路由定義最正確? 情境題
4. 小明寫了以下 API,但訪問 /search 時收到錯誤。最可能的原因是什麼? 錯誤診斷
@app.get(“/search”)
def search(q: str, page: int = 1):
return {“q”: q, “page”: page}
# 錯誤訊息:
# {“detail”:[{“loc”:[“query”,”q”],”msg”:”field required”,”type”:”value_error.missing”}]}
5. 小華寫了以下 API,訪問 /users/abc 時收到 422 錯誤。如何正確診斷這個問題? 錯誤診斷
@app.get(“/users/{user_id}”)
def get_user(user_id: int):
return {“user_id”: user_id}
# 訪問 /users/abc 時的錯誤:
# {“detail”:[{“loc”:[“path”,”user_id”],”msg”:”value is not a valid integer”,”type”:”type_error.integer”}]}