Python | Web フレームワーク:パスパラメータ

Python
スポンサーリンク

概要(パスパラメータ=「URLの中の変数」)

パスパラメータは、

/users/123 の「123」
/items/abc の「abc」

のように、URL の一部を「変数」として受け取る仕組みです。

Web フレームワーク(FastAPI / Flask / Django など)では、
この「URL の一部」を関数の引数として受け取れるようにしておくことで、

「どのユーザーを表示するか」
「どの商品を取得するか」

といった「対象を指定する情報」をスマートに扱えます。

ここでは FastAPI を例にしながら、パスパラメータを初心者向けにじっくり解説していきます。


パスパラメータの一番基本形(FastAPI)

固定パスとパスパラメータの違いを知る

まず、「普通の固定パス」と「パスパラメータ」を対比してみます。

固定パスの例(いつも同じ URL):

from fastapi import FastAPI

app = FastAPI()

@app.get("/hello")
def say_hello():
    return {"message": "hello"}
Python

これは GET /hello に対してだけ反応します。
URL の一部が変わると別ルートになります。

次に、パスパラメータの例です。

from fastapi import FastAPI

app = FastAPI()

@app.get("/users/{user_id}")
def get_user(user_id: str):
    return {"user_id": user_id}
Python

このエンドポイントは、

/users/1
/users/taro
/users/xyz-123

など、{user_id} の部分が何であっても受け取ることができます。

この {user_id} が「パスパラメータ」です。

URL のテンプレート /users/{user_id} を定義しておくことで、
user_id という名前の引数に、URL の一部が自動で渡されます。

名前の対応が重要({user_id} ↔ user_id 引数)

さっきの例で、ルートと関数の定義をもう一度見てください。

@app.get("/users/{user_id}")
def get_user(user_id: str):
    ...
Python

{user_id}user_id
名前が完全に一致しています。

FastAPI は、「パスに書かれた {user_id}」「関数の引数 user_id」を見て、そこを紐づけています。

もし名前を変えると、FastAPI は対応できません。

@app.get("/users/{user_id}")
def get_user(id: str):  # NG: 名前が違う
    ...
Python

このように書くと、「user_id というパラメータを引数に渡そうとしているのに、id が定義されている」となって不整合です。

パスパラメータでは「名前の一致」が絶対ルールです。


型ヒントでパスパラメータを「強く」する(ここが FastAPI の美味しいところ)

文字列だけでなく、整数などの型も指定できる

FastAPI の強みは、「パスパラメータに型を付けられる」ことです。

@app.get("/users/{user_id}")
def get_user(user_id: int):
    return {"user_id": user_id}
Python

この場合、FastAPI は user_id を「整数」として扱います。

URL 側は文字列ですが、フレームワークが内部で int(user_id) を試みます。

もし /users/10 のように数字が来れば、user_id は整数 10 になります。
もし /users/abc のように数字以外が来たら、「整数に変換できない」と判断して 400 エラー(Bad Request)を返してくれます。

つまり、

user_id: int と書くだけで、「整数であることのチェック」を自動でやってくれる

わけです。

これが「型ヒントがバリデーションになる」という FastAPI の気持ち良さです。

よく使う型の例

パスパラメータに使える型はいろいろありますが、初心者ならまずは次のあたりを押さえておけば十分です。

str: 文字列。何でも受け取れる。
int: 整数。123 など。
float: 実数。1.23 など。

これらはすべて、「型ヒントを書く → FastAPI が変換+チェックしてくれる」流れです。

例えば、商品のIDが整数なら int、コードが文字列なら str にしておくと、
「ありえない値(文字列のIDを期待しているのに数字だけ」など)を早めに弾けます。


複数のパスパラメータを使う(URL の構造をきれいに設計する)

例:年月日をパスで受け取る

日付を /reports/2025/01/01 のように分けて渡したい場合を考えます。

from fastapi import FastAPI

app = FastAPI()

@app.get("/reports/{year}/{month}/{day}")
def daily_report(year: int, month: int, day: int):
    return {
        "date": f"{year:04d}-{month:02d}-{day:02d}"
    }
Python

このルーティングは、

GET /reports/2025/1/2year=2025, month=1, day=2
GET /reports/2024/12/31year=2024, month=12, day=31

という風に動きます。

ここでも「名前の対応」と「型」が重要です。

パス:

/reports/{year}/{month}/{day}

関数:

def daily_report(year: int, month: int, day: int):

このように位置と名前を揃えておくことで、FastAPI が自動でマッピングしてくれます。

パス設計の考え方(見た瞬間に意味が分かる URL にする)

パスパラメータを使うときに意識してほしいのは、「URL の形だけで意味が伝わるか」です。

/reports/2025/01/01 → 2025-01-01 のレポート
/users/123/orders → ユーザー123の注文一覧

このように、URL を見ただけで「ああ、このリソースだな」と分かる構造にしておくと、
自分も他人も API が理解しやすくなります。


パスパラメータとクエリパラメータの違い(ここをはっきりさせる)

パスパラメータは「対象そのもの」、クエリは「条件」

とても大事な区別なので、少し丁寧に説明します。

例えば、ユーザーの注文履歴を取る API を考えてみます。

GET /users/123/orders
GET /users/123/orders?limit=10&offset=20

この場合、

123 → ユーザーという「対象そのもの」を特定する情報(パスパラメータ)
limit=10offset=20 → 「どう取得するか」の条件(クエリパラメータ)

という分け方になります。

FastAPI で書くとこうです。

from fastapi import FastAPI

app = FastAPI()

@app.get("/users/{user_id}/orders")
def list_orders(user_id: int, limit: int = 10, offset: int = 0):
    return {
        "user_id": user_id,
        "limit": limit,
        "offset": offset,
        "orders": []
    }
Python

user_id はパスパラメータとして URL に含め、
limitoffset はクエリパラメータとして ?limit=...&offset=... で渡します。

設計の目安としては、

「この情報がないと、どのリソースか分からない」
→ パスパラメータ

「この情報がなくても、とりあえずは取れる(ただし条件なし)」
→ クエリパラメータ

と考えると、だいたいしっくり来ます。


パスパラメータを使うときの注意ポイント(初心者がハマりやすいところ)

1. パスの順番と具体性(/users/me と /users/{user_id})

FastAPI では、「どのルートにマッチさせるか」がパスの定義順や具体性に影響されます。

例えば、次のようなコードを考えます。

from fastapi import FastAPI

app = FastAPI()

@app.get("/users/me")
def get_me():
    return {"user": "current"}

@app.get("/users/{user_id}")
def get_user(user_id: str):
    return {"user_id": user_id}
Python

この場合、

/users/me は「固定パス」
/users/{user_id} は「何でもマッチするパス」

FastAPI は「より具体的なパスを優先」するので、
/users/me にアクセスしたときは get_me が呼ばれます。

もし順番を逆にしても(FastAPI はパスの具体性で判断するので)大丈夫ですが、
Flask などフレームワークによっては「上から順にマッチ」もあるので、
「固定パス」と「なんでもパラメータ」の組み合わせには注意したほうが安全です。

FastAPI では、

/users/me
/users/{user_id}

のような組み合わせはよく使われます

ログイン中ユーザー専用 → /users/me
任意のユーザー → /users/{user_id}

のような形で使い分けられます。

2. 型変換とエラー(パスに入る値は信じない)

user_id: int と書いた場合、FastAPI が型変換とチェックをしてくれますが、
「失敗することも前提」で考える必要があります。

/users/abc のようなリクエストが来るかもしれない
/reports/2025/13/32 のように、存在しない日付が来るかもしれない

こういう場合は、型レベルでは OK(全部 int)でも、意味的には NG です。

year, month, day を受け取ったあとで、
Python の datetime で日付として有効か確認するなど、
「意味的なバリデーション」は自分で書く必要があります。

例えば:

from fastapi import FastAPI, HTTPException
from datetime import date

app = FastAPI()

@app.get("/reports/{year}/{month}/{day}")
def daily_report(year: int, month: int, day: int):
    try:
        target_date = date(year, month, day)
    except ValueError:
        raise HTTPException(status_code=400, detail="Invalid date")
    return {"date": target_date.isoformat()}
Python

こうしておくと、

/reports/2025/1/2 → OK
/reports/2025/13/32 → 400(無効な日付)

という動きになります。

パスパラメータの「型チェック」は FastAPI がやってくれますが、
「値として妥当かどうか」のチェックは自分の仕事、という意識を持っておくと安全です。


まとめ(パスパラメータは「URLでリソースを指すための変数」)

パスパラメータを、自分の中で整理するとこうなります。

パスパラメータは、/users/{id}{id} のように、「URLの一部」を変数として受け取る仕組みで、対象のリソース(ユーザー・商品・日付など)を指定するのに使う。
FastAPI では、ルートに /users/{user_id} と書き、関数に user_id: int などと型付き引数を定義すると、URL → 引数 のマッピング+型チェックを自動でやってくれる。
「その情報がないとどのリソースか分からない」ものはパスパラメータ、「あると便利だがなくてもとりあえず動く」条件はクエリパラメータにする、という分け方を意識すると URL 設計がきれいになる。
パスパラメータを複数組み合わせて /reports/{year}/{month}/{day} のような構造を作ると、「URLを見ただけで意味が分かる」APIになる。
型チェックはやってくれるが、「意味として妥当か」(日付・範囲・存在チェックなど)は自分でバリデーションを書く必要がある。

タイトルとURLをコピーしました