Path Parameters and Query Parameters — Precision Routing Design
ルーティング設計は都市の道路計画のようなものです。Path Parameters は住所 (正確な位置), Query Parameters は絞り込み条件 (範囲の限定)であり, この2つが連携してはじめて目的地に素早くたどり着けます。
1. 学ぶ内容
- Path Parameters:自動型変換, バリデーション,
Path()制約 (gt/ge/lt/le) - Query Parameters:Optional/Required, デフォルト値,
Query()高度なバリデーション (alias/description/deprecated) - 複数パラメータの組み合わせ順序のルールとよくある落とし穴
- 文字列列挙パラメータ:
Enum— Path と Query での活用 - Alice の PriceTracker シナリオ:商品 ID で価格検索, カテゴリと価格範囲でフィルタリング
2. Alice のリアルストーリー
(1) ペインポイント:商品検索 API のパラメータが混乱
Alice の PriceTracker は複数の検索方法に対応する必要があります:商品 ID による正確な検索, カテゴリと価格範囲によるフィルタリング, ソート順によるページネーション閲覧です。Bob はフロントエンドから category=electronics&min_price=10&max_price=999 を送信しましたが, Alice の Flask コードは各パラメータを手動でパースしています。型変換でエラーが起きやすく, 負の価格や無効なソートフィールドに対するバリデーションもないため, 本番環境でのインシデントが頻発しています。
(2) FastAPI におけるパラメータバリデーションの解決策
FastAPI は型ヒントを使用してパラメータを自動的にパース・バリデーションします。Path() と Query() は宣言的な制約を提供し, 無効なパラメータは自動的に 422 エラーをトリガーします。
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/products/{product_id}")
async def get_product(
product_id: int = Path(gt=0, description="Product ID must be positive"),
category: str | None = Query(None, max_length=50),
):
return {"product_id": product_id, "category": category}
(3) 成果
パラメータバリデーションコードは 30 行から 3 行に削減され, 422 エラーレスポンスにはバリデーション失敗の具体的な詳細が自動的に含まれるようになり, Bob はどのパラメータが間違っているかをすぐに特定できます。API ドキュメントにもすべての制約が自動的に表示されます。
3. Path Parameters の詳細解説
(1) 基本的な Path Parameters
Path Parameters は URL パスの一部であり, {param} 構文で定義します。FastAPI は型ヒントに基づいて自動的に変換します。
sequenceDiagram
participant Client
participant Router as FastAPI Router
participant Converter as Type Converter
participant Validator as Path Validator
participant Handler as View Function
Client->>Router: GET /products/42
Router->>Converter: Extract "42" from path
Converter->>Converter: int("42") → 42
Converter->>Validator: product_id=42 (int)
Validator->>Validator: Check gt=0 → 42 > 0 ✓
Validator->>Handler: get_product(product_id=42)
Handler-->>Client: {"product_id": 42}
| Path Parameter 型 | URL 例 | Python 型 | 自動変換 |
|---|---|---|---|
| 整数 | /products/42 |
int |
"42" → 42 |
| 浮動小数点数 | /prices/9.99 |
float |
"9.99" → 9.99 |
| 文字列 | /categories/electronics |
str |
そのまま |
| Path | /files/src/main.py |
Path |
/ を含む文字列 |
(1) ▶ サンプル:基本的な Path Parameters と型変換
from fastapi import FastAPI
app = FastAPI()
@app.get("/products/{product_id}")
async def get_product(product_id: int):
# FastAPI は自動的に "42" を int(42) に変換
# ユーザーが /products/abc を送信 → 422 エラー
return {"product_id": product_id, "type": str(type(product_id))}
出力:
INFO: 127.0.0.1:50123 - "GET /api/items HTTP/1.1" 200 OK
出力 (
/products/42):
{"product_id": 42, "type": "<class 'int'>"}
(2) Path() 制約バリデーション
Path() は Path Parameters に数値範囲や文字列長などの制約を追加します。これらは OpenAPI ドキュメントに自動的に反映されます。
| 制約パラメータ | 対象型 | 意味 |
|---|---|---|
gt |
int/float | より大きい (>) |
ge |
int/float | 以上 (>=) |
lt |
int/float | より小さい (<) |
le |
int/float | 以下 (<=) |
min_length |
str | 最小長 |
max_length |
str | 最大長 |
pattern |
str | 正規表現マッチ |
description |
全型 | OpenAPI 説明 |
(2) ▶ サンプル:Path() 数値制約
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/products/{product_id}")
async def get_product(
product_id: int = Path(
gt=0,
le=1000000,
description="Product ID: 正の整数, 最大100万",
),
):
return {"product_id": product_id}
出力:
INFO: 127.0.0.1:50123 - "GET /api/items HTTP/1.1" 200 OK
出力 (
/products/-1は 422 を返す):
{
"detail": [
{
"loc": ["path", "product_id"],
"msg": "Input should be greater than 0",
"type": "greater_than"
}
]
}
4. Query Parameters の詳細解説
(1) 基本的な Query Parameters
Query Parameters は URL の ? に続くキーと値のペアです。関数パラメータとして宣言され, デフォルト値を持つパラメータは任意です。
| Query Parameter 型 | 宣言方法 | 必須 |
|---|---|---|
| 必須 | category: str |
はい |
| 任意 (デフォルト) | category: str = "all" |
いいえ |
| 任意 (None) | `category: str | None = None` |
(1) ▶ サンプル:Query Parameter の基本
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/prices")
async def search_prices(
category: str | None = Query(None, max_length=50, description="商品カテゴリ"),
min_price: float = Query(0.0, ge=0, description="最低価格 (USD)"),
max_price: float = Query(999999.0, le=999999, description="最高価格 (USD)"),
):
return {
"category": category,
"price_range": f"${min_price} - ${max_price}",
}
出力:
INFO: 127.0.0.1:50123 - "GET /api/items HTTP/1.1" 200 OK
出力 (
/prices?category=electronics&min_price=10&max_price=500):
{"category": "electronics", "price_range": "$10.0 - $500.0"}
(2) Query() 高度なオプション
| オプション | 機能 | 例 |
|---|---|---|
alias |
パラメータのエイリアス (例:キャメルケース→スネークケース) | Query(alias="minPrice") |
deprecated |
廃止予定としてマーク | Query(deprecated=True) |
title |
OpenAPI タイトル | Query(title="Category Filter") |
description |
OpenAPI 説明 | Query(description="...") |
examples |
サンプル値 | Query(examples=["electronics"]) |
(2) ▶ サンプル:alias と deprecated
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/products")
async def list_products(
sort_by: str = Query(
"name",
alias="sortBy",
description="Sort field: name, price, created_at",
),
old_filter: str | None = Query(
None,
deprecated=True,
description="sort_by を代わりに使用",
),
):
return {"sort_by": sort_by}
出力:
# 関数定義成功
5. 列挙パラメータ
(1) 文字列列挙で可能な値を制限
パラメータが固定の値しか取れない場合, Enum 制約を使用すると, FastAPI はドキュメントにドロップダウンメニューを自動表示します。
(1) ▶ サンプル:列挙 Path Parameters
from enum import Enum
from fastapi import FastAPI
class Category(str, Enum):
electronics = "electronics"
clothing = "clothing"
food = "food"
books = "books"
app = FastAPI()
@app.get("/categories/{category}")
async def get_category(category: Category):
return {
"category": category,
"value": category.value,
"label": category.name,
}
出力:
INFO: 127.0.0.1:50123 - "GET /api/items HTTP/1.1" 200 OK
出力 (
/categories/electronics):
{"category": "electronics", "value": "electronics", "label": "electronics"}
(2) ▶ サンプル:列挙 Query Parameters とソート
from enum import Enum
from fastapi import FastAPI, Query
class SortOrder(str, Enum):
asc = "asc"
desc = "desc"
app = FastAPI()
@app.get("/products")
async def list_products(
sort_order: SortOrder = Query(SortOrder.asc),
limit: int = Query(20, ge=1, le=100),
offset: int = Query(0, ge=0),
):
return {
"sort": sort_order.value,
"limit": limit,
"offset": offset,
}
出力:
# 関数定義成功
6. 複数パラメータの組み合わせと落とし穴
(1) パラメータ宣言の順序ルール
FastAPI のパラメータ型判定ルール:パスに {param} が含まれていれば Path Parameter, そうでなければ Query Parameter です (型アノテーションのあるパラメータは必須, デフォルト値のあるものは任意)。
| 順序 | パラメータ型 | 判定基準 |
|---|---|---|
| 1 | Path Parameter | URL に {param} が含まれる |
| 2 | Query Parameter (必須) | デフォルト値なし, パスに含まれない |
| 3 | Query Parameter (任意) | デフォルト値または None を持つ |
(1) ▶ サンプル:複数パラメータの組み合わせ — PriceTracker 商品検索
from fastapi import FastAPI, Path, Query
from enum import Enum
class Category(str, Enum):
electronics = "electronics"
clothing = "clothing"
food = "food"
app = FastAPI()
@app.get("/products/{product_id}/prices")
async def get_product_prices(
product_id: int = Path(gt=0, description="商品 ID"),
category: Category | None = Query(None, description="カテゴリでフィルタ"),
min_price: float = Query(0.0, ge=0, description="最低価格 (USD)"),
max_price: float = Query(99999.0, ge=0, description="最高価格 (USD)"),
sort: str = Query("date", pattern="^(date|price)$"),
limit: int = Query(20, ge=1, le=100),
offset: int = Query(0, ge=0),
):
return {
"product_id": product_id,
"category": category,
"price_range": [min_price, max_price],
"sort": sort,
"pagination": {"limit": limit, "offset": offset},
}
出力:
# 関数定義成功
(2) よくある落とし穴
| 落とし穴 | 誤った構文 | 正しい構文 |
|---|---|---|
| Path Parameter を任意にする | product_id: int = None |
Path Parameter は必須 |
| デフォルト値と Query の競合 | limit: int = 20, Query(ge=1) |
limit: int = Query(20, ge=1) |
| 任意パラメータの None | category: str = None |
`category: str |
Enum で str 基底クラスを使わない |
class Cat(Enum): |
class Cat(str, Enum): |
7. 総合サンプル
Path Parameters, Query Parameters, Enum 制約は柔軟な API 構築の基盤です。以下では, Path 制約, Query ページネーション, Enum フィルタリングを組み合わせます。
from fastapi import FastAPI, Path, Query
from enum import Enum
app = FastAPI()
class SortOrder(str, Enum):
asc = "asc"
desc = "desc"
PRODUCTS = [{"id": i, "name": f"Product-{i}", "price": i * 10.0} for i in range(1, 101)]
@app.get("/products/{product_id}")
async def get_product(
product_id: int = Path(gt=0, description="商品 ID"),
sort: SortOrder = Query(SortOrder.asc),
limit: int = Query(10, ge=1, le=100),
offset: int = Query(0, ge=0),
):
return {
"product_id": product_id,
"sort": sort.value,
"limit": limit,
"offset": offset,
}
出力:
GET /products/5?sort=desc&limit=20&offset=10 → {"product_id":5,"sort":"desc","limit":20,"offset":10}
GET /products/0 → 422 Validation Error (product_id must be > 0)
❓ よくある質問
category: str は必須, category: str = "all" は任意です。Query(...) を使って明示的に必須とマークすることもできます。gt=0 は値が > 0 (0 を含まない), ge=0 は >= 0 (0 を含む)を意味します。ID 型のパラメータには通常 gt=0, 価格型のパラメータには ge=0 を使用します。Query(max_length=N) で文字列の長さを制限し, Query(ge=N, le=M) で数値範囲を制限します。📖 まとめ
- Path Parameters は URL の
{param}で宣言し, FastAPI が型ヒントに基づいて自動変換・バリデーションします Path()は数値範囲制約 (gt/ge/lt/le)と文字列制約 (min_length/max_length)を追加します- Query Parameters は関数パラメータとして宣言し, デフォルト値のあるものは任意, ないものは必須です
Query()はalias/deprecated/description/examplesなどの高度なオプションをサポートします- 列挙パラメータ (
str, Enum)は使用可能な値を制限し, ドキュメントにドロップダウンメニューを自動表示します
📝 練習問題
- 基本問題 (難易度 ⭐):GET エンドポイント
/items/{item_id}を作成し,item_id(正の整数)を入力として受け取り,{"item_id": item_id}を返すようにしてください。ヒント:item_id: int = Path(gt=0) - 応用問題 (難易度 ⭐⭐):PriceTracker の
/productsクエリエンドポイントを作成し, 3 つの Query Parameters をサポートしてください:category(任意の文字列, 最大50文字),min_price(≥0),max_price(≤999999)。ヒント:Query(None, max_length=50) - チャレンジ問題 (難易度 ⭐⭐⭐):
/products/{product_id}/pricesエンドポイントを作成し, Path Parameters (product_id > 0), 列挙 Query Parameters (SortOrder: asc/desc), ページネーションパラメータ (limit 1-100, offset ≥ 0)を使用して, 無効な入力が 422 エラーを返すことを確認してください。ヒント:SortOrder(str, Enum)と複数のQuery()を定義
---|



