コンテンツへスキップ

パスパラメーターと数値の検証

クエリパラメーターで Query を使用して追加の検証とメタデータを宣言できるのと同様に、パスパラメーターで Path を使用して同じ種類の検証とメタデータを宣言できます。

パスのインポート

まず、fastapi から Path をインポートし、Annotated をインポートします。

from typing import Annotated

from fastapi import FastAPI, Path, Query

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(
    item_id: Annotated[int, Path(title="The ID of the item to get")],
    q: Annotated[str | None, Query(alias="item-query")] = None,
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results
🤓 その他のバージョンとバリアント
from typing import Annotated, Union

from fastapi import FastAPI, Path, Query

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(
    item_id: Annotated[int, Path(title="The ID of the item to get")],
    q: Annotated[Union[str, None], Query(alias="item-query")] = None,
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results
from typing import Union

from fastapi import FastAPI, Path, Query
from typing_extensions import Annotated

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(
    item_id: Annotated[int, Path(title="The ID of the item to get")],
    q: Annotated[Union[str, None], Query(alias="item-query")] = None,
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results

ヒント

可能であれば`Annotated`バージョンを使用することをお勧めします。

from fastapi import FastAPI, Path, Query

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(
    item_id: int = Path(title="The ID of the item to get"),
    q: str | None = Query(default=None, alias="item-query"),
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results

ヒント

可能であれば`Annotated`バージョンを使用することをお勧めします。

from typing import Union

from fastapi import FastAPI, Path, Query

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(
    item_id: int = Path(title="The ID of the item to get"),
    q: Union[str, None] = Query(default=None, alias="item-query"),
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results

情報

FastAPI はバージョン 0.95.0 で Annotated のサポートを追加し(そして推奨し始めました)。

古いバージョンを使用している場合、Annotated を使用しようとするとエラーが発生します。

Annotated を使用する前に、FastAPI のバージョンを 0.95.1 以上にアップグレードしてください。

メタデータの宣言

Query と同じパラメーターをすべて宣言できます。

たとえば、パスパラメーター item_idtitle メタデータ値を宣言するには、次のように入力します。

from typing import Annotated

from fastapi import FastAPI, Path, Query

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(
    item_id: Annotated[int, Path(title="The ID of the item to get")],
    q: Annotated[str | None, Query(alias="item-query")] = None,
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results
🤓 その他のバージョンとバリアント
from typing import Annotated, Union

from fastapi import FastAPI, Path, Query

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(
    item_id: Annotated[int, Path(title="The ID of the item to get")],
    q: Annotated[Union[str, None], Query(alias="item-query")] = None,
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results
from typing import Union

from fastapi import FastAPI, Path, Query
from typing_extensions import Annotated

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(
    item_id: Annotated[int, Path(title="The ID of the item to get")],
    q: Annotated[Union[str, None], Query(alias="item-query")] = None,
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results

ヒント

可能であれば`Annotated`バージョンを使用することをお勧めします。

from fastapi import FastAPI, Path, Query

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(
    item_id: int = Path(title="The ID of the item to get"),
    q: str | None = Query(default=None, alias="item-query"),
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results

ヒント

可能であれば`Annotated`バージョンを使用することをお勧めします。

from typing import Union

from fastapi import FastAPI, Path, Query

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(
    item_id: int = Path(title="The ID of the item to get"),
    q: Union[str, None] = Query(default=None, alias="item-query"),
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results

パスパラメーターはパスの一部である必要があるため、常に必須です。None で宣言したり、デフォルト値を設定しても、何も影響はなく、常に必須となります。

必要に応じてパラメーターを並べ替える

ヒント

Annotated を使用する場合は、これはそれほど重要ではないか、必要ありません。

クエリパラメーター q を必須の str として宣言したいとします。

そして、そのパラメーターに他に何も宣言する必要がないため、Query を使用する必要は実際にはありません。

しかし、item_id パスパラメーターには Path を使用する必要があります。そして、何らかの理由で Annotated を使用したくないとします。

デフォルト値を持たない値の前に「デフォルト」を持つ値を置くと、Python は文句を言います。

しかし、それらを並べ替えて、デフォルト値を持たない値(クエリパラメーター q)を最初に置くことができます。

FastAPI にとっては問題ありません。名前、型、デフォルトの宣言(QueryPath など)によってパラメーターを検出するため、順序は気にしません。

したがって、関数を次のように宣言できます。

ヒント

可能であれば`Annotated`バージョンを使用することをお勧めします。

from fastapi import FastAPI, Path

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(q: str, item_id: int = Path(title="The ID of the item to get")):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results
🤓 その他のバージョンとバリアント
from typing import Annotated

from fastapi import FastAPI, Path

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(
    q: str, item_id: Annotated[int, Path(title="The ID of the item to get")]
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results
from fastapi import FastAPI, Path
from typing_extensions import Annotated

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(
    q: str, item_id: Annotated[int, Path(title="The ID of the item to get")]
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results

ただし、Annotated を使用する場合、Query()Path() の関数パラメーターのデフォルト値を使用しないため、この問題は発生せず、* を使用する必要もありません。

from typing import Annotated

from fastapi import FastAPI, Path

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(
    q: str, item_id: Annotated[int, Path(title="The ID of the item to get")]
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results
🤓 その他のバージョンとバリアント
from fastapi import FastAPI, Path
from typing_extensions import Annotated

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(
    q: str, item_id: Annotated[int, Path(title="The ID of the item to get")]
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results

ヒント

可能であれば`Annotated`バージョンを使用することをお勧めします。

from fastapi import FastAPI, Path

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(q: str, item_id: int = Path(title="The ID of the item to get")):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results

必要に応じてパラメーターを並べ替える、裏技

ヒント

Annotated を使用する場合は、これはそれほど重要ではないか、必要ありません。

便利なちょっとした裏技がありますが、頻繁に必要になることはありません。

次のようにしたい場合

  • Query もデフォルト値もなしで q クエリパラメーターを宣言する
  • Path を使用してパスパラメーター item_id を宣言する
  • それらを異なる順序にする
  • Annotated を使用しない

...Python には、それに対する少し特別な構文があります。

関数の最初のパラメーターとして * を渡します。

Python はその * で何も行いませんが、それに続くすべてのパラメーターをキーワード引数(キーと値のペア)、別名 kwargs として呼び出す必要があることを認識します。デフォルト値がない場合でもです。

from fastapi import FastAPI, Path

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(*, item_id: int = Path(title="The ID of the item to get"), q: str):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results
🤓 その他のバージョンとバリアント
from typing import Annotated

from fastapi import FastAPI, Path

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(
    item_id: Annotated[int, Path(title="The ID of the item to get")], q: str
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results
from fastapi import FastAPI, Path
from typing_extensions import Annotated

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(
    item_id: Annotated[int, Path(title="The ID of the item to get")], q: str
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results

Annotated を使用するとより良い

Annotated を使用する場合、関数パラメーターのデフォルト値を使用しないため、この問題は発生せず、* を使用する必要もありません。

from typing import Annotated

from fastapi import FastAPI, Path

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(
    item_id: Annotated[int, Path(title="The ID of the item to get")], q: str
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results
🤓 その他のバージョンとバリアント
from fastapi import FastAPI, Path
from typing_extensions import Annotated

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(
    item_id: Annotated[int, Path(title="The ID of the item to get")], q: str
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results

ヒント

可能であれば`Annotated`バージョンを使用することをお勧めします。

from fastapi import FastAPI, Path

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(*, item_id: int = Path(title="The ID of the item to get"), q: str):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results

数値の検証: 以上

QueryPath(および後で説明するその他のもの)を使用すると、数値の制約を宣言できます。

ここで、ge=1 を指定すると、item_id1「以上」(greater than or equal)の整数である必要があります。

from typing import Annotated

from fastapi import FastAPI, Path

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(
    item_id: Annotated[int, Path(title="The ID of the item to get", ge=1)], q: str
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results
🤓 その他のバージョンとバリアント
from fastapi import FastAPI, Path
from typing_extensions import Annotated

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(
    item_id: Annotated[int, Path(title="The ID of the item to get", ge=1)], q: str
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results

ヒント

可能であれば`Annotated`バージョンを使用することをお勧めします。

from fastapi import FastAPI, Path

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(
    *, item_id: int = Path(title="The ID of the item to get", ge=1), q: str
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results

数値の検証: より大きい、以下

同じことが以下にも当てはまります。

  • gt: greater than(より大きい)
  • le: less than or equal(以下)
from typing import Annotated

from fastapi import FastAPI, Path

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(
    item_id: Annotated[int, Path(title="The ID of the item to get", gt=0, le=1000)],
    q: str,
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results
🤓 その他のバージョンとバリアント
from fastapi import FastAPI, Path
from typing_extensions import Annotated

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(
    item_id: Annotated[int, Path(title="The ID of the item to get", gt=0, le=1000)],
    q: str,
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results

ヒント

可能であれば`Annotated`バージョンを使用することをお勧めします。

from fastapi import FastAPI, Path

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(
    *,
    item_id: int = Path(title="The ID of the item to get", gt=0, le=1000),
    q: str,
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results

数値の検証: 浮動小数点数、より大きい、より小さい

数値の検証は float 値にも機能します。

ここで、gt を宣言でき、単に ge だけでなくそれが重要になります。たとえば、値が 1 未満であっても、0 より大きいことを要求できます。

したがって、0.5 は有効な値ですが、0.00 は有効ではありません。

そして、lt も同様です。

from typing import Annotated

from fastapi import FastAPI, Path, Query

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(
    *,
    item_id: Annotated[int, Path(title="The ID of the item to get", ge=0, le=1000)],
    q: str,
    size: Annotated[float, Query(gt=0, lt=10.5)],
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    if size:
        results.update({"size": size})
    return results
🤓 その他のバージョンとバリアント
from fastapi import FastAPI, Path, Query
from typing_extensions import Annotated

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(
    *,
    item_id: Annotated[int, Path(title="The ID of the item to get", ge=0, le=1000)],
    q: str,
    size: Annotated[float, Query(gt=0, lt=10.5)],
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    if size:
        results.update({"size": size})
    return results

ヒント

可能であれば`Annotated`バージョンを使用することをお勧めします。

from fastapi import FastAPI, Path, Query

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(
    *,
    item_id: int = Path(title="The ID of the item to get", ge=0, le=1000),
    q: str,
    size: float = Query(gt=0, lt=10.5),
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    if size:
        results.update({"size": size})
    return results

まとめ

QueryPath(およびまだ見ていない他のクラス)を使用すると、クエリパラメーターと文字列の検証と同様の方法でメタデータと文字列の検証を宣言できます。

また、数値の検証も宣言できます。

  • gt: greater than(より大きい)
  • ge: greater than or equal(以上)
  • lt: less than(より小さい)
  • le: less than or equal(以下)

情報

QueryPath、および後で説明する他のクラスは、共通の Param クラスのサブクラスです。

これらすべては、これまでに見てきた追加の検証とメタデータに同じパラメーターを共有しています。

技術的な詳細

fastapi から QueryPath などをインポートすると、実際には関数です。

呼び出されると、同じ名前のクラスのインスタンスを返します。

したがって、関数である Query をインポートします。そして、それを呼び出すと、同じく Query という名前のクラスのインスタンスが返されます。

これらの関数が存在するのは(クラスを直接使用するのではなく)、エディタがそれらの型に関するエラーをマークしないようにするためです。

これにより、これらのエラーを無視するようにカスタム設定を追加することなく、通常のエディタとコーディングツールを使用できます。