コンテンツにスキップ

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

🌐 Translation by AI and humans

This translation was made by AI guided by humans. 🤝

It could have mistakes of misunderstanding the original meaning, or looking unnatural, etc. 🤖

You can improve this translation by helping us guide the AI LLM better.

English version

クエリパラメータに対して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
🤓 Other versions and variants
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

Tip

Prefer to use the Annotated version if possible.

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

Tip

Prefer to use the Annotated version if possible.

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_idに対してtitleのメタデータを宣言するには以下のようにします:

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
🤓 Other versions and variants
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

Tip

Prefer to use the Annotated version if possible.

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

Tip

Prefer to use the Annotated version if possible.

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など)で検出され、順番は気にしません。

そのため、以下のように関数を宣言することができます:

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
🤓 Other versions and variants
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

ただし、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
🤓 Other versions and variants

Tip

Prefer to use the Annotated version if possible.

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を使う場合、これはおそらくそれほど重要でも必要でもありません。

これは小さなトリックで、便利な場合がありますが、頻繁に必要になることはありません。

次のことをしたい場合:

  • qクエリパラメータをQueryもデフォルト値もなしで宣言する
  • パスパラメータitem_idPathを使って宣言する
  • それらを別の順番にする
  • 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
🤓 Other versions and variants
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

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
🤓 Other versions and variants

Tip

Prefer to use the Annotated version if possible.

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「より大きいgか、同じe」整数でなければなりません。

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
🤓 Other versions and variants

Tip

Prefer to use the Annotated version if possible.

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
🤓 Other versions and variants

Tip

Prefer to use the Annotated version if possible.

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
🤓 Other versions and variants

Tip

Prefer to use the Annotated version if possible.

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

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

この方法によって、これらのエラーを無視するための設定を追加することなく、通常のエディタやコーディングツールを使用することができます。