【FastAPI 教學】#03 路由與參數處理

測驗:FastAPI 路由與參數處理

共 5 題,點選答案後會立即顯示結果

1. 在 FastAPI 中,下列哪種參數會從網址路徑中取得?

@app.get(“/users/{user_id}”) def get_user(user_id: int): return {“user_id”: user_id}
  • A. Path 參數
  • B. Query 參數
  • C. Body 參數
  • D. Header 參數

2. 當訪問 /items?skip=5&limit=20 時,下列哪個函式定義可以正確接收這些參數?

  • A. def get_items(skip, limit):
  • B. def get_items(skip: int = 0, limit: int = 10):
  • C. def get_items({skip}, {limit}):
  • D. def get_items(query_params):

3. 在 FastAPI 中,如何讓一個參數變成「必填」?

  • A. 使用 required=True 標註
  • B. 使用 @required 裝飾器
  • C. 不給參數預設值
  • D. 使用 Optional 標註

4. 下列程式碼中,Path(ge=1) 的作用是什麼?

@app.get(“/users/{user_id}”) def get_user(user_id: int = Path(ge=1)): return {“user_id”: user_id}
  • A. 設定 user_id 的預設值為 1
  • B. 限制 user_id 必須大於等於 1
  • C. 設定 user_id 的最大值為 1
  • D. 讓 user_id 變成可選參數

5. 在下列函式中,FastAPI 如何判斷 user_idskip 分別是什麼類型的參數?

@app.get(“/users/{user_id}/items”) def get_user_items(user_id: int, skip: int = 0): …
  • A. 兩者都是 Query 參數
  • B. 兩者都是 Path 參數
  • C. user_id 是 Query 參數,skip 是 Path 參數
  • D. user_id 是 Path 參數(出現在路徑裡),skip 是 Query 參數(不在路徑裡)

一句話說明

讓 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 題,包含情境題與錯誤診斷題。

1. 你正在開發一個電商 API,需要實作「取得單一商品」的端點。商品 ID 是正整數,不能為 0 或負數。哪個實作方式最符合需求? 情境題

  • A. @app.get("/products/{product_id}")
    def get_product(product_id: int):
  • B. @app.get("/products")
    def get_product(product_id: int = 0):
  • C. @app.get("/products/{product_id}")
    def get_product(product_id: int = Path(ge=1)):
  • D. @app.get("/products/{product_id}")
    def get_product(product_id: str):

2. 你需要實作一個搜尋 API,需求如下:關鍵字 (q) 是必填、頁碼 (page) 預設為 1、每頁筆數 (limit) 預設為 10 且最大 100。哪個實作最正確? 情境題

  • A. def search(q: str = None, page: int = 1, limit: int = 10):
  • B. def search(q: str, page: int = 1, limit: int = Query(default=10, le=100)):
  • C. def search(q: str = "", page: int = 1, limit: int = 100):
  • D. def search(q: Optional[str], page: int = 1, limit: int = 10):

3. 你正在開發部落格 API,需要取得某個用戶的所有文章,並支援分頁。網址格式應該是 /users/123/posts?skip=0&limit=10。哪個路由定義最正確? 情境題

  • A. @app.get("/users/posts")
    def get_posts(user_id: int, skip: int = 0, limit: int = 10):
  • B. @app.get("/users/{user_id}/{posts}")
    def get_posts(user_id: int, posts: str, skip: int = 0, limit: int = 10):
  • C. @app.get("/users/{user_id}/posts/{skip}/{limit}")
    def get_posts(user_id: int, skip: int, limit: int):
  • D. @app.get("/users/{user_id}/posts")
    def get_posts(user_id: int, skip: int = 0, limit: int = 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”}]}
  • A. 路由定義錯誤,應該使用 /search/{q}
  • B. 參數 q 是必填但沒有給值,應該訪問 /search?q=關鍵字
  • C. 參數 q 應該改成 q: int
  • D. FastAPI 不支援 Query 參數

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”}]}
  • A. 路由寫錯了,應該改成 /users/user_id
  • B. 應該加上 Path() 驗證
  • C. 傳入的 “abc” 不是有效的整數,FastAPI 自動驗證型別失敗
  • D. 應該把 user_id: int 改成 user_id: str 才能接受任意值

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *