FastAPI路徑參數進階:動態路由與參數校驗

在使用FastAPI開發接口時,路徑參數(Path Parameters)是一種非常靈活的傳參方式,比如/users/{user_id}中的user_id。但FastAPI的路徑參數遠不止基礎用法,它們支持動態路由參數校驗,讓接口更靈活、更健壯。

一、回顧基礎路徑參數

首先,我們先快速回顧一下路徑參數的基礎用法。比如,定義一個根據用戶ID返回用戶信息的接口:

from fastapi import FastAPI

app = FastAPI()

# 基礎路徑參數:user_id是路徑參數,默認類型爲str
@app.get("/users/{user_id}")
async def get_user(user_id: str):
    return {"user_id": user_id, "message": f"獲取用戶 {user_id} 的信息"}

當訪問/users/123時,user_id會被自動識別爲字符串"123"。但FastAPI允許我們顯式指定參數類型(如intfloat),讓參數自動轉換和校驗。

二、動態路由進階:讓路徑參數更靈活

動態路由指的是路徑參數可以根據實際需求“動態變化”,支持多種參數組合或特殊格式。

1. 路徑參數類型自動轉換

FastAPI會自動嘗試將路徑參數轉換爲指定類型(如intfloat)。例如,即使URL中傳的是字符串"123",只要我們定義user_id: int,FastAPI會自動將其轉爲整數:

@app.get("/users/{user_id}")
async def get_user(user_id: int):  # 自動轉換爲int類型
    return {"user_id": user_id, "type": type(user_id)}  # 輸出:{"user_id": 123, "type": <class 'int'>}

如果參數類型轉換失敗(如/users/abc中傳"abc"int類型的user_id),FastAPI會直接返回422 Validation Error,避免非法數據進入接口。

2. 可選路徑參數

有時路徑參數可能不是必須的,比如/items/{item_id}/details/{sub_id},其中sub_id可能是可選的。這時可以用Optional類型+默認值:

from typing import Optional

@app.get("/items/{item_id}/details/{sub_id}")
async def get_item_details(
    item_id: int,  # 必須參數
    sub_id: Optional[int] = None  # 可選參數,默認None
):
    result = {"item_id": item_id}
    if sub_id:
        result["sub_id"] = sub_id
    return result

訪問/items/123/details/456會返回{"item_id": 123, "sub_id": 456},而訪問/items/123(不帶sub_id)會返回{"item_id": 123}

3. 路徑參數的正則表達式限制

如果需要嚴格限制路徑參數的格式(如只能是字母、數字組合),可以用Pathpattern參數配合正則表達式:

from fastapi import Path

@app.get("/orders/{order_code}")
async def get_order(order_code: str = Path(..., pattern="^[A-Z0-9]{8}$")):
    # order_code必須是8位大寫字母或數字(如"ABC12345")
    return {"order_code": order_code}

這裏pattern="^[A-Z0-9]{8}$"表示:
- ^$:匹配字符串開頭和結尾
- [A-Z0-9]:允許大寫字母或數字
- {8}:必須連續出現8次

三、參數校驗進階:讓接口更安全

光有動態路由還不夠,FastAPI支持對路徑參數進行嚴格校驗(如範圍、枚舉值等),確保傳入的數據合法。

1. 用Path限制參數範圍

使用Path函數可以給路徑參數設置最小值、最大值、是否必須等規則。例如,定義商品ID必須在1到100之間:

@app.get("/products/{item_id}")
async def get_product(
    item_id: int = Path(
        ...,  # 必傳參數(...表示必填)
        ge=1,  # ge=1:大於等於1
        le=100,  # le=100:小於等於100
        description="商品ID必須是1-100之間的整數"
    )
):
    return {"item_id": item_id, "message": f"獲取商品 {item_id} 的詳情"}
  • ge(greater than or equal):最小值
  • le(less than or equal):最大值
  • 若傳入不合法參數(如/products/0/products/101),FastAPI會直接返回422錯誤,並提示“商品ID必須是1-100之間的整數”。
2. 枚舉類型路徑參數

如果參數只能是特定枚舉值(如商品分類只能是"book""electronics""clothes"),可以用EnumLiteral實現:

from enum import Enum

class Category(str, Enum):
    BOOK = "book"
    ELECTRONICS = "electronics"
    CLOTHES = "clothes"

@app.get("/products/{category}/{item_id}")
async def get_product_by_category(
    category: Category,  # 枚舉類型,只能傳預定義值
    item_id: int = Path(ge=1, le=100)
):
    return {
        "category": category.value,
        "item_id": item_id,
        "message": f"獲取 {category.value} 分類下的商品 {item_id}"
    }

此時訪問/products/electronics/123會返回正確結果,但訪問/products/music/123會報錯(music不是枚舉值)。

四、動態路由+參數校驗的實際應用

結合動態路由和參數校驗,可以構建更通用、更安全的接口。例如:

from fastapi import FastAPI, Path, Query
from typing import Optional

app = FastAPI()

# 動態生成路由:根據用戶ID和訂單類型返回訂單
@app.get("/users/{user_id}/orders/{order_type}")
async def get_orders(
    user_id: int = Path(ge=1, description="用戶ID必須是正整數"),
    order_type: str = Path(
        ..., 
        pattern="^(pending|completed|cancelled)$",  # 訂單狀態只能是這三種
        description="訂單類型必須是pending/completed/cancelled"
    ),
    page: int = Query(1, ge=1, le=10, description="頁碼必須是1-10")  # 注意:Query用於查詢參數,這裏僅作示例
):
    return {
        "user_id": user_id,
        "order_type": order_type,
        "page": page,
        "message": f"獲取用戶 {user_id}{order_type} 訂單,第 {page} 頁"
    }
  • 動態路由/users/{user_id}/orders/{order_type}支持任意用戶ID和訂單類型(只要符合規則)。
  • 參數校驗user_id必須是正整數,order_type必須是預定義狀態,page必須是1-10的整數。

五、總結

FastAPI的路徑參數進階特性讓我們能:
1. 動態路由:通過靈活的路徑參數組合,支持多種業務場景(如多維度查詢、層級化接口)。
2. 參數校驗:自動轉換類型、限制範圍、枚舉值校驗,避免非法數據進入接口,提升接口健壯性。

這些特性讓接口開發更簡單,同時減少了手動校驗參數的代碼量。如果你正在開發需要靈活路徑和嚴格數據校驗的API,FastAPI的路徑參數進階用法會是你的得力助手!

小提示:訪問FastAPI自動生成的Swagger文檔(/docs),可以直觀看到參數校驗規則,方便測試和調試。

小夜