コンテンツへスキップ

リクエスト例データの宣言

アプリが受信できるデータの例を宣言できます。

いくつかの方法があります。

Pydantic モデル内の追加の JSON スキーマ データ

Pydantic モデルの examples を宣言し、生成された JSON スキーマに追加できます。

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None

    model_config = {
        "json_schema_extra": {
            "examples": [
                {
                    "name": "Foo",
                    "description": "A very nice Item",
                    "price": 35.4,
                    "tax": 3.2,
                }
            ]
        }
    }


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return results
🤓 その他のバージョンとバリアント
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None

    model_config = {
        "json_schema_extra": {
            "examples": [
                {
                    "name": "Foo",
                    "description": "A very nice Item",
                    "price": 35.4,
                    "tax": 3.2,
                }
            ]
        }
    }


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return results
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None

    class Config:
        schema_extra = {
            "examples": [
                {
                    "name": "Foo",
                    "description": "A very nice Item",
                    "price": 35.4,
                    "tax": 3.2,
                }
            ]
        }


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return results
🤓 その他のバージョンとバリアント
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None

    class Config:
        schema_extra = {
            "examples": [
                {
                    "name": "Foo",
                    "description": "A very nice Item",
                    "price": 35.4,
                    "tax": 3.2,
                }
            ]
        }


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return results

この追加情報は、そのモデルの出力 JSON スキーマ にそのまま追加され、API ドキュメントで使用されます。

Pydantic バージョン 2 では、Pydantic のドキュメント: Configuration で説明されているように、dict を取る属性 model_config を使用します。

"json_schema_extra" を、生成された JSON スキーマに表示したい追加データ (examples を含む) を含む dict で設定できます。

Pydantic バージョン 1 では、Pydantic のドキュメント: Schema customization で説明されているように、内部クラス Configschema_extra を使用します。

schema_extra を、生成された JSON スキーマに表示したい追加データ (examples を含む) を含む dict で設定できます。

ヒント

同じ手法を使用して JSON スキーマを拡張し、独自のカスタム追加情報を追加することもできます。

たとえば、フロントエンドのユーザーインターフェイスのメタデータを追加するために使用できます。

情報

OpenAPI 3.1.0 (FastAPI 0.99.0 以降で使用) は、JSON スキーマ 標準の一部である examples のサポートを追加しました。

それ以前は、単一の例を示すキーワード example のみをサポートしていました。これは OpenAPI 3.1.0 でもサポートされていますが、非推奨であり、JSON スキーマ標準の一部ではありません。そのため、exampleexamples に移行することをお勧めします。🤓

詳細については、このページの最後をご覧ください。

Field の追加引数

Pydantic モデルで Field() を使用する場合、追加の examples も宣言できます。

from fastapi import FastAPI
from pydantic import BaseModel, Field

app = FastAPI()


class Item(BaseModel):
    name: str = Field(examples=["Foo"])
    description: str | None = Field(default=None, examples=["A very nice Item"])
    price: float = Field(examples=[35.4])
    tax: float | None = Field(default=None, examples=[3.2])


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return results
🤓 その他のバージョンとバリアント
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel, Field

app = FastAPI()


class Item(BaseModel):
    name: str = Field(examples=["Foo"])
    description: Union[str, None] = Field(default=None, examples=["A very nice Item"])
    price: float = Field(examples=[35.4])
    tax: Union[float, None] = Field(default=None, examples=[3.2])


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return results

JSON スキーマ - OpenAPI 内の examples

以下のいずれかを使用する場合

  • Path()
  • Query()
  • Header()
  • Cookie()
  • Body()
  • Form()
  • File()

OpenAPI 内の JSON スキーマ に追加情報とともに examples のグループを宣言することもできます。

examples を含む Body

ここでは、Body() で予期されるデータの例を 1 つ含む examples を渡します。

from typing import Annotated

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


@app.put("/items/{item_id}")
async def update_item(
    item_id: int,
    item: Annotated[
        Item,
        Body(
            examples=[
                {
                    "name": "Foo",
                    "description": "A very nice Item",
                    "price": 35.4,
                    "tax": 3.2,
                }
            ],
        ),
    ],
):
    results = {"item_id": item_id, "item": item}
    return results
🤓 その他のバージョンとバリアント
from typing import Annotated, Union

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None


@app.put("/items/{item_id}")
async def update_item(
    item_id: int,
    item: Annotated[
        Item,
        Body(
            examples=[
                {
                    "name": "Foo",
                    "description": "A very nice Item",
                    "price": 35.4,
                    "tax": 3.2,
                }
            ],
        ),
    ],
):
    results = {"item_id": item_id, "item": item}
    return results
from typing import Union

from fastapi import Body, FastAPI
from pydantic import BaseModel
from typing_extensions import Annotated

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None


@app.put("/items/{item_id}")
async def update_item(
    item_id: int,
    item: Annotated[
        Item,
        Body(
            examples=[
                {
                    "name": "Foo",
                    "description": "A very nice Item",
                    "price": 35.4,
                    "tax": 3.2,
                }
            ],
        ),
    ],
):
    results = {"item_id": item_id, "item": item}
    return results

ヒント

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

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


@app.put("/items/{item_id}")
async def update_item(
    item_id: int,
    item: Item = Body(
        examples=[
            {
                "name": "Foo",
                "description": "A very nice Item",
                "price": 35.4,
                "tax": 3.2,
            }
        ],
    ),
):
    results = {"item_id": item_id, "item": item}
    return results

ヒント

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

from typing import Union

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None


@app.put("/items/{item_id}")
async def update_item(
    item_id: int,
    item: Item = Body(
        examples=[
            {
                "name": "Foo",
                "description": "A very nice Item",
                "price": 35.4,
                "tax": 3.2,
            }
        ],
    ),
):
    results = {"item_id": item_id, "item": item}
    return results

ドキュメント UI の例

上記のいずれかの方法を使用すると、/docs で次のように表示されます。

複数の examples を含む Body

もちろん、複数の examples を渡すこともできます。

from typing import Annotated

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


@app.put("/items/{item_id}")
async def update_item(
    *,
    item_id: int,
    item: Annotated[
        Item,
        Body(
            examples=[
                {
                    "name": "Foo",
                    "description": "A very nice Item",
                    "price": 35.4,
                    "tax": 3.2,
                },
                {
                    "name": "Bar",
                    "price": "35.4",
                },
                {
                    "name": "Baz",
                    "price": "thirty five point four",
                },
            ],
        ),
    ],
):
    results = {"item_id": item_id, "item": item}
    return results
🤓 その他のバージョンとバリアント
from typing import Annotated, Union

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None


@app.put("/items/{item_id}")
async def update_item(
    *,
    item_id: int,
    item: Annotated[
        Item,
        Body(
            examples=[
                {
                    "name": "Foo",
                    "description": "A very nice Item",
                    "price": 35.4,
                    "tax": 3.2,
                },
                {
                    "name": "Bar",
                    "price": "35.4",
                },
                {
                    "name": "Baz",
                    "price": "thirty five point four",
                },
            ],
        ),
    ],
):
    results = {"item_id": item_id, "item": item}
    return results
from typing import Union

from fastapi import Body, FastAPI
from pydantic import BaseModel
from typing_extensions import Annotated

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None


@app.put("/items/{item_id}")
async def update_item(
    *,
    item_id: int,
    item: Annotated[
        Item,
        Body(
            examples=[
                {
                    "name": "Foo",
                    "description": "A very nice Item",
                    "price": 35.4,
                    "tax": 3.2,
                },
                {
                    "name": "Bar",
                    "price": "35.4",
                },
                {
                    "name": "Baz",
                    "price": "thirty five point four",
                },
            ],
        ),
    ],
):
    results = {"item_id": item_id, "item": item}
    return results

ヒント

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

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


@app.put("/items/{item_id}")
async def update_item(
    *,
    item_id: int,
    item: Item = Body(
        examples=[
            {
                "name": "Foo",
                "description": "A very nice Item",
                "price": 35.4,
                "tax": 3.2,
            },
            {
                "name": "Bar",
                "price": "35.4",
            },
            {
                "name": "Baz",
                "price": "thirty five point four",
            },
        ],
    ),
):
    results = {"item_id": item_id, "item": item}
    return results

ヒント

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

from typing import Union

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None


@app.put("/items/{item_id}")
async def update_item(
    *,
    item_id: int,
    item: Item = Body(
        examples=[
            {
                "name": "Foo",
                "description": "A very nice Item",
                "price": 35.4,
                "tax": 3.2,
            },
            {
                "name": "Bar",
                "price": "35.4",
            },
            {
                "name": "Baz",
                "price": "thirty five point four",
            },
        ],
    ),
):
    results = {"item_id": item_id, "item": item}
    return results

これを行うと、例はそのボディデータの内部 JSON スキーマ の一部になります。

しかし、この記事の執筆時点では、ドキュメント UI を表示するツールである Swagger UI は、JSON スキーマ 内のデータの複数の例の表示をサポートしていません。しかし、回避策については以下をお読みください。

OpenAPI 固有の examples

JSON スキーマexamples をサポートする以前から、OpenAPI は examples とも呼ばれる別のフィールドをサポートしていました。

この OpenAPI 固有の examples は、OpenAPI 仕様の別のセクションにあります。各 パス操作 の詳細にあり、各 JSON スキーマ内にはありません。

そして、Swagger UI はこの特定の examples フィールドを以前からサポートしています。そのため、これを使用してドキュメント UI でさまざまな例を 表示 できます。

この OpenAPI 固有のフィールド examples の形式は、複数の例 を持つ dict (list ではなく) であり、それぞれに OpenAPI にも追加される追加情報が含まれます。

これは OpenAPI に含まれる各 JSON スキーマ内には含まれず、外側の パス操作 に直接含まれます。

openapi_examples パラメータの使用

FastAPI では、openapi_examples パラメータを使用して OpenAPI 固有の examples を宣言できます。

  • Path()
  • Query()
  • Header()
  • Cookie()
  • Body()
  • Form()
  • File()

dict のキーは各例を識別し、各値は別の dict です。

examples 内の各特定の例の dict には、以下が含まれます。

  • summary: 例の短い説明。
  • description: Markdown テキストを含む長い説明。
  • value: 表示される実際の例。たとえば dict です。
  • externalValue: value の代替で、例を指す URL です。ただし、これは value ほど多くのツールでサポートされていない可能性があります。

次のように使用できます。

from typing import Annotated

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


@app.put("/items/{item_id}")
async def update_item(
    *,
    item_id: int,
    item: Annotated[
        Item,
        Body(
            openapi_examples={
                "normal": {
                    "summary": "A normal example",
                    "description": "A **normal** item works correctly.",
                    "value": {
                        "name": "Foo",
                        "description": "A very nice Item",
                        "price": 35.4,
                        "tax": 3.2,
                    },
                },
                "converted": {
                    "summary": "An example with converted data",
                    "description": "FastAPI can convert price `strings` to actual `numbers` automatically",
                    "value": {
                        "name": "Bar",
                        "price": "35.4",
                    },
                },
                "invalid": {
                    "summary": "Invalid data is rejected with an error",
                    "value": {
                        "name": "Baz",
                        "price": "thirty five point four",
                    },
                },
            },
        ),
    ],
):
    results = {"item_id": item_id, "item": item}
    return results
🤓 その他のバージョンとバリアント
from typing import Annotated, Union

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None


@app.put("/items/{item_id}")
async def update_item(
    *,
    item_id: int,
    item: Annotated[
        Item,
        Body(
            openapi_examples={
                "normal": {
                    "summary": "A normal example",
                    "description": "A **normal** item works correctly.",
                    "value": {
                        "name": "Foo",
                        "description": "A very nice Item",
                        "price": 35.4,
                        "tax": 3.2,
                    },
                },
                "converted": {
                    "summary": "An example with converted data",
                    "description": "FastAPI can convert price `strings` to actual `numbers` automatically",
                    "value": {
                        "name": "Bar",
                        "price": "35.4",
                    },
                },
                "invalid": {
                    "summary": "Invalid data is rejected with an error",
                    "value": {
                        "name": "Baz",
                        "price": "thirty five point four",
                    },
                },
            },
        ),
    ],
):
    results = {"item_id": item_id, "item": item}
    return results
from typing import Union

from fastapi import Body, FastAPI
from pydantic import BaseModel
from typing_extensions import Annotated

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None


@app.put("/items/{item_id}")
async def update_item(
    *,
    item_id: int,
    item: Annotated[
        Item,
        Body(
            openapi_examples={
                "normal": {
                    "summary": "A normal example",
                    "description": "A **normal** item works correctly.",
                    "value": {
                        "name": "Foo",
                        "description": "A very nice Item",
                        "price": 35.4,
                        "tax": 3.2,
                    },
                },
                "converted": {
                    "summary": "An example with converted data",
                    "description": "FastAPI can convert price `strings` to actual `numbers` automatically",
                    "value": {
                        "name": "Bar",
                        "price": "35.4",
                    },
                },
                "invalid": {
                    "summary": "Invalid data is rejected with an error",
                    "value": {
                        "name": "Baz",
                        "price": "thirty five point four",
                    },
                },
            },
        ),
    ],
):
    results = {"item_id": item_id, "item": item}
    return results

ヒント

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

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


@app.put("/items/{item_id}")
async def update_item(
    *,
    item_id: int,
    item: Item = Body(
        openapi_examples={
            "normal": {
                "summary": "A normal example",
                "description": "A **normal** item works correctly.",
                "value": {
                    "name": "Foo",
                    "description": "A very nice Item",
                    "price": 35.4,
                    "tax": 3.2,
                },
            },
            "converted": {
                "summary": "An example with converted data",
                "description": "FastAPI can convert price `strings` to actual `numbers` automatically",
                "value": {
                    "name": "Bar",
                    "price": "35.4",
                },
            },
            "invalid": {
                "summary": "Invalid data is rejected with an error",
                "value": {
                    "name": "Baz",
                    "price": "thirty five point four",
                },
            },
        },
    ),
):
    results = {"item_id": item_id, "item": item}
    return results

ヒント

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

from typing import Union

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None


@app.put("/items/{item_id}")
async def update_item(
    *,
    item_id: int,
    item: Item = Body(
        openapi_examples={
            "normal": {
                "summary": "A normal example",
                "description": "A **normal** item works correctly.",
                "value": {
                    "name": "Foo",
                    "description": "A very nice Item",
                    "price": 35.4,
                    "tax": 3.2,
                },
            },
            "converted": {
                "summary": "An example with converted data",
                "description": "FastAPI can convert price `strings` to actual `numbers` automatically",
                "value": {
                    "name": "Bar",
                    "price": "35.4",
                },
            },
            "invalid": {
                "summary": "Invalid data is rejected with an error",
                "value": {
                    "name": "Baz",
                    "price": "thirty five point four",
                },
            },
        },
    ),
):
    results = {"item_id": item_id, "item": item}
    return results

ドキュメント UI の OpenAPI の例

Body()openapi_examples を追加すると、/docs は次のようになります。

技術的な詳細

ヒント

すでに FastAPI バージョン 0.99.0 以降 を使用している場合は、これらの詳細は スキップ しても構いません。

これらは、OpenAPI 3.1.0 が利用可能になる前の古いバージョンに関連しています。

これを簡単な OpenAPI と JSON スキーマの 歴史の授業 と考えてください。🤓

警告

これらは、標準の JSON スキーマOpenAPI に関する非常に技術的な詳細です。

上記のアイデアがすでに機能している場合は、それで十分かもしれません。これらの詳細はおそらく必要ありませんので、スキップしても構いません。

OpenAPI 3.1.0 より前は、OpenAPI は古い修正版の JSON スキーマ を使用していました。

JSON スキーマには examples がなかったため、OpenAPI は独自の修正版に独自の example フィールドを追加しました。

OpenAPI はまた、仕様の他の部分にも exampleexamples フィールドを追加しました。

情報

この古い OpenAPI 固有の examples パラメータは、FastAPI 0.103.0 以降 openapi_examples となりました。

JSON スキーマの examples フィールド

しかしその後、JSON スキーマは仕様の新しいバージョンに examples フィールドを追加しました。

そして新しい OpenAPI 3.1.0 は、この新しいフィールド examples を含む最新バージョン (JSON スキーマ 2020-12) に基づいていました。

そして現在、この新しい examples フィールドは、非推奨となった古い単一の (カスタム) example フィールドよりも優先されます。

JSON スキーマのこの新しい examples フィールドは、OpenAPI の他の場所 (上記で説明) のように追加のメタデータを持つ辞書ではなく、単なる例の list です。

情報

OpenAPI 3.1.0 が JSON スキーマとのこの新しいシンプルな統合でリリースされた後も、しばらくの間、自動ドキュメントを提供するツールである Swagger UI は OpenAPI 3.1.0 をサポートしていませんでした (バージョン 5.0.0 🎉 以降はサポートしています)。

そのため、FastAPI の 0.99.0 より前のバージョンは、3.1.0 より低いバージョンの OpenAPI を使用していました。

Pydantic と FastAPI の examples

Pydantic モデル内に schema_extra または Field(examples=["something"]) を使用して examples を追加すると、その例はその Pydantic モデルの JSON スキーマ に追加されます。

そして、Pydantic モデルのその JSON スキーマ は API の OpenAPI に含まれ、ドキュメント UI で使用されます。

FastAPI の 0.99.0 より前のバージョン (0.99.0 以降は新しい OpenAPI 3.1.0 を使用) で、他のユーティリティ (Query()Body() など) で example または examples を使用した場合、それらの例はそのデータを記述する JSON スキーマに追加されず (OpenAPI 独自の JSON スキーマのバージョンにも追加されず)、OpenAPI の パス操作 宣言に直接追加されました (JSON スキーマを使用する OpenAPI の部分の外側)。

しかし、FastAPI 0.99.0 以降が OpenAPI 3.1.0 (JSON スキーマ 2020-12 を使用) と Swagger UI 5.0.0 以降を使用するようになったため、すべてがより一貫性があり、例が JSON スキーマに含まれるようになりました。

Swagger UI と OpenAPI 固有の examples

Swagger UI は複数の JSON スキーマの例をサポートしていなかったため (2023-08-26 時点)、ユーザーはドキュメントに複数の例を表示する方法がありませんでした。

これを解決するため、FastAPI 0.103.0 は、新しいパラメータ openapi_examples で同じ古い OpenAPI 固有の examples フィールドの宣言を 追加でサポート しました。🤓

概要

昔は歴史があまり好きじゃないと言っていたのに…今では「技術史」の授業をしているなんて。😅

要するに、FastAPI 0.99.0 以降にアップグレードしてください。そうすれば、物事がはるかに シンプルで一貫性があり、直感的 になり、これらの歴史的な詳細をすべて知る必要がなくなります。😎