コンテンツへスキップ

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

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

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

Note

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

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

ヒント

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

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

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

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

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

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

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

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

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「以上」の整数である必要があります。

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.0または0は有効ではありません。

そして、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という名前のクラスのインスタンスが返されます。

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

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