コンテンツにスキップ

クエリパラメータモデル

AI coding agents

Use the official FastAPI skill for your installed version. Install it from your project directory:

uvx library-skills

See Develop with AI.

🌐 AI と人間による翻訳

この翻訳は、人間のガイドに基づいて AI によって作成されました。🤝

原文の意図を取り違えていたり、不自然な表現になっている可能性があります。🤖

AI LLM をより適切に誘導するのを手伝う ことで、この翻訳を改善できます。

英語版

もし関連する複数のクエリパラメータから成るグループがあるなら、それらを宣言するために、Pydanticモデルを作成できます。

こうすることで、複数の場所でそのモデルを再利用でき、バリデーションやメタデータを、すべてのパラメータに対して一度に宣言できます。😎

備考

この機能は、FastAPIのバージョン 0.115.0 からサポートされています。🤓

Pydanticモデルを使ったクエリパラメータ

必要なクエリパラメータをPydanticモデルで宣言し、さらに、そのパラメータを Query として宣言しましょう:

from typing import Annotated, Literal

from fastapi import FastAPI, Query
from pydantic import BaseModel, Field

app = FastAPI()


class FilterParams(BaseModel):
    limit: int = Field(100, gt=0, le=100)
    offset: int = Field(0, ge=0)
    order_by: Literal["created_at", "updated_at"] = "created_at"
    tags: list[str] = []


@app.get("/items/")
async def read_items(filter_query: Annotated[FilterParams, Query()]):
    return filter_query
🤓 Other versions and variants

Tip

Prefer to use the Annotated version if possible.

from typing import Literal

from fastapi import FastAPI, Query
from pydantic import BaseModel, Field

app = FastAPI()


class FilterParams(BaseModel):
    limit: int = Field(100, gt=0, le=100)
    offset: int = Field(0, ge=0)
    order_by: Literal["created_at", "updated_at"] = "created_at"
    tags: list[str] = []


@app.get("/items/")
async def read_items(filter_query: FilterParams = Query()):
    return filter_query

FastAPIは、リクエストのクエリパラメータからそれぞれのフィールドのデータを抽出し、定義したPydanticモデルを提供します。

ドキュメントの確認

対話的APIドキュメント /docs でクエリパラメータを確認できます:

余分なクエリパラメータを禁止する

特定の(あまり一般的ではないかもしれない)ユースケースで、受け取りたいクエリパラメータを制限したい場合があります。

Pydanticのモデル設定を使って、あらゆる extra フィールドを forbid にできます。

from typing import Annotated, Literal

from fastapi import FastAPI, Query
from pydantic import BaseModel, Field

app = FastAPI()


class FilterParams(BaseModel):
    model_config = {"extra": "forbid"}

    limit: int = Field(100, gt=0, le=100)
    offset: int = Field(0, ge=0)
    order_by: Literal["created_at", "updated_at"] = "created_at"
    tags: list[str] = []


@app.get("/items/")
async def read_items(filter_query: Annotated[FilterParams, Query()]):
    return filter_query
🤓 Other versions and variants

Tip

Prefer to use the Annotated version if possible.

from typing import Literal

from fastapi import FastAPI, Query
from pydantic import BaseModel, Field

app = FastAPI()


class FilterParams(BaseModel):
    model_config = {"extra": "forbid"}

    limit: int = Field(100, gt=0, le=100)
    offset: int = Field(0, ge=0)
    order_by: Literal["created_at", "updated_at"] = "created_at"
    tags: list[str] = []


@app.get("/items/")
async def read_items(filter_query: FilterParams = Query()):
    return filter_query

もしクライアントがクエリパラメータとして余分なデータを送ろうとすると、エラーレスポンスが返されます。

例えば、クライアントがクエリパラメータ tool に、値 plumbus を設定して送ろうとすると:

https://example.com/items/?limit=10&tool=plumbus

クエリパラメータ tool が許可されていないことを伝えるエラーレスポンスが返されます。

{
    "detail": [
        {
            "type": "extra_forbidden",
            "loc": ["query", "tool"],
            "msg": "Extra inputs are not permitted",
            "input": "plumbus"
        }
    ]
}

パラメータモデルの組み合わせ

複数のクエリパラメータモデルを宣言し、個別のクエリパラメータや依存関係と組み合わせることができます。

from typing import Annotated

from fastapi import FastAPI, Query
from pydantic import BaseModel, Field

app = FastAPI()


class Pagination(BaseModel):
    limit: int = Field(10, ge=1)
    offset: int = Field(0, ge=0)


class Filters(BaseModel):
    tags: list[str] = []


@app.get("/items/")
def read_items(
    pagination: Annotated[Pagination, Query()],
    filters: Annotated[Filters, Query()],
    search: str | None = None,
):
    return {"pagination": pagination, "filters": filters, "search": search}
🤓 Other versions and variants

Tip

Prefer to use the Annotated version if possible.

from fastapi import FastAPI, Query
from pydantic import BaseModel, Field

app = FastAPI()


class Pagination(BaseModel):
    limit: int = Field(10, ge=1)
    offset: int = Field(0, ge=0)


class Filters(BaseModel):
    tags: list[str] = []


@app.get("/items/")
def read_items(
    pagination: Pagination = Query(),
    filters: Filters = Query(),
    search: str | None = None,
):
    return {"pagination": pagination, "filters": filters, "search": search}

リクエストパラメータは同じ階層のままです。

https://example.com/items/?limit=5&offset=10&tags=red&tags=blue&search=shirt

クエリ文字列に pagination や filters キーはありません。各モデルは、それぞれのデフォルト値、フィールドバリデータ、モデルバリデータを使って、クエリパラメータを独立して検証します。モデルや個別のパラメータを依存関係で宣言した場合も同様です。

複数のモデルがパラメータ名やエイリアスを共有している場合、各モデルはそのリクエストパラメータを独立して検証します。独立した値には、異なる名前やエイリアスを使用してください。OpenAPIでは、依存関係と共有するパラメータと同様に、共有パラメータは一度だけ記載されるため、共有する宣言では同じ型と制約を記述する必要があります。

各モデルの extra 設定は、他のモデルや依存関係で宣言されたものも含め、すべてのクエリパラメータに適用されます。extra="forbid" の場合、そのモデルに含まれないパラメータはすべて拒否されます。extra="allow" の場合、それらのパラメータはモデルの余分なフィールドとして含まれます。

これは Header モデルと Cookie モデルでも機能します。

任意のクエリパラメータモデル

クエリパラメータモデルに | None とデフォルト値 None を指定して宣言すると、そのグループを任意にできます。

from datetime import date
from typing import Annotated

from fastapi import FastAPI, Query
from pydantic import BaseModel

app = FastAPI()


class DateRange(BaseModel):
    start: date
    end: date


@app.get("/items/")
async def read_items(
    limit: int = 10,
    date_range: Annotated[DateRange | None, Query()] = None,
):
    return {"limit": limit, "date_range": date_range}
🤓 Other versions and variants

Tip

Prefer to use the Annotated version if possible.

from datetime import date

from fastapi import FastAPI, Query
from pydantic import BaseModel

app = FastAPI()


class DateRange(BaseModel):
    start: date
    end: date


@app.get("/items/")
async def read_items(
    limit: int = 10,
    date_range: DateRange | None = Query(default=None),
):
    return {"limit": limit, "date_range": date_range}

start も end も送信されない場合、date_range は None になります。どちらかが送信された場合、FastAPIはモデルを検証し、両方のフィールドを必須とします。

デフォルト値なしで | None を使用した場合、パラメータは引き続き必須です。

余分なパラメータはモデルの extra 設定に従います。無視される余分なパラメータがあっても、モデルが存在するとはみなされません。

OpenAPIでは、グループのフィールドが個別に記載され、任意としてマークされます。

任意のヘッダーパラメータモデルやクッキーパラメータモデルも宣言できます。

まとめ

FastAPIでは、クエリパラメータを宣言するために、Pydanticモデルを使用できます。😎

豆知識

ネタバレ注意: Pydanticモデルはクッキーやヘッダーの宣言にも使用できますが、その内容については後のチュートリアルで学びます。🤫