リクエスト例データの宣言¶
アプリが受信できるデータの例を宣言できます。
いくつかの方法があります。
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 で説明されているように、内部クラス Config
と schema_extra
を使用します。
schema_extra
を、生成された JSON スキーマに表示したい追加データ (examples
を含む) を含む dict
で設定できます。
ヒント
同じ手法を使用して JSON スキーマを拡張し、独自のカスタム追加情報を追加することもできます。
たとえば、フロントエンドのユーザーインターフェイスのメタデータを追加するために使用できます。
情報
OpenAPI 3.1.0 (FastAPI 0.99.0 以降で使用) は、JSON スキーマ 標準の一部である examples
のサポートを追加しました。
それ以前は、単一の例を示すキーワード example
のみをサポートしていました。これは OpenAPI 3.1.0 でもサポートされていますが、非推奨であり、JSON スキーマ標準の一部ではありません。そのため、example
を examples
に移行することをお勧めします。🤓
詳細については、このページの最後をご覧ください。
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 はまた、仕様の他の部分にも example
と examples
フィールドを追加しました。
Parameter Object
(仕様内) は FastAPI のもので使用されました。Path()
Query()
Header()
Cookie()
Request Body Object
、フィールドcontent
、Media Type Object
(仕様内) は FastAPI のもので使用されました。Body()
File()
Form()
情報
この古い 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 以降にアップグレードしてください。そうすれば、物事がはるかに シンプルで一貫性があり、直感的 になり、これらの歴史的な詳細をすべて知る必要がなくなります。😎