コンテンツにスキップ

レスポンスモデル - 戻り値の型

**パス操作関数**の**戻り値の型**にアノテーションを付けることで、レスポンスに使用される型を宣言できます。

関数の**パラメータ**に入力データに使用するのと同じ方法で**型アノテーション**を使用できます。Pydanticモデル、リスト、辞書、整数、ブール値などのスカラー値を使用できます。

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
    tags: list[str] = []


@app.post("/items/")
async def create_item(item: Item) -> Item:
    return item


@app.get("/items/")
async def read_items() -> list[Item]:
    return [
        Item(name="Portal Gun", price=42.0),
        Item(name="Plumbus", price=32.0),
    ]
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
    tags: list[str] = []


@app.post("/items/")
async def create_item(item: Item) -> Item:
    return item


@app.get("/items/")
async def read_items() -> list[Item]:
    return [
        Item(name="Portal Gun", price=42.0),
        Item(name="Plumbus", price=32.0),
    ]
from typing import List, 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
    tags: List[str] = []


@app.post("/items/")
async def create_item(item: Item) -> Item:
    return item


@app.get("/items/")
async def read_items() -> List[Item]:
    return [
        Item(name="Portal Gun", price=42.0),
        Item(name="Plumbus", price=32.0),
    ]

FastAPIはこの戻り値の型を使用して、以下のことを行います。

  • 返されたデータの**検証**を行います。
    • データが無効な場合(例:フィールドが欠落している場合)、それは*あなたの*アプリコードが壊れており、想定される値を返していないことを意味し、間違ったデータを返す代わりにサーバーエラーを返します。こうすれば、あなたとあなたのクライアントは、期待されるデータとデータの形状を受け取ることが確実になります。
  • OpenAPIの *パス操作* に、レスポンスの**JSONスキーマ**を追加します。
    • これは**自動ドキュメント**で使用されます。
    • また、自動クライアントコード生成ツールでも使用されます。

しかし、最も重要なのは

  • 出力データを戻り値の型で定義されている内容に**制限およびフィルタリング**します。
    • これは**セキュリティ**にとって特に重要です。以下で詳しく説明します。

response_model パラメータ

型が宣言しているものと正確に一致しないデータを返す必要がある、または返したい場合があります。

たとえば、**辞書**またはデータベースオブジェクトを**返したい**が、**Pydanticモデルとして宣言したい**場合があります。こうすることで、Pydanticモデルは、返されたオブジェクト(例:辞書またはデータベースオブジェクト)のすべてのデータドキュメント、検証などを行います。

戻り値の型アノテーションを追加した場合、ツールとエディターは、関数が宣言された型(例:Pydanticモデル)とは異なる型(例:dict)を返していることを示す(正しい)エラーを報告します。

このような場合は、戻り値の型ではなく、*パス操作デコレータ*パラメータ response_model を使用できます。

*パス操作* のいずれかで response_model パラメータを使用できます

  • @app.get()
  • @app.post()
  • @app.put()
  • @app.delete()
  • など
from typing import Any

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
    tags: list[str] = []


@app.post("/items/", response_model=Item)
async def create_item(item: Item) -> Any:
    return item


@app.get("/items/", response_model=list[Item])
async def read_items() -> Any:
    return [
        {"name": "Portal Gun", "price": 42.0},
        {"name": "Plumbus", "price": 32.0},
    ]
from typing import Any, 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
    tags: list[str] = []


@app.post("/items/", response_model=Item)
async def create_item(item: Item) -> Any:
    return item


@app.get("/items/", response_model=list[Item])
async def read_items() -> Any:
    return [
        {"name": "Portal Gun", "price": 42.0},
        {"name": "Plumbus", "price": 32.0},
    ]
from typing import Any, List, 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
    tags: List[str] = []


@app.post("/items/", response_model=Item)
async def create_item(item: Item) -> Any:
    return item


@app.get("/items/", response_model=List[Item])
async def read_items() -> Any:
    return [
        {"name": "Portal Gun", "price": 42.0},
        {"name": "Plumbus", "price": 32.0},
    ]

注記

response_model は、「デコレータ」メソッド (getpost など) のパラメータであることに注意してください。すべてのパラメータやボディのように、*パス操作関数* のパラメータではありません。

response_model は、Pydanticモデルフィールドに宣言するのと同じ型を受け取ります。そのため、Pydanticモデルにすることができますが、たとえば、List[Item] のようなPydanticモデルの list にすることもできます。

FastAPIはこの response_model を使用して、すべてのデータドキュメント、検証などを行い、また、出力データをその型宣言に**変換およびフィルタリング**します。

ヒント

エディタ、mypy などで厳密な型チェックを行っている場合は、関数の戻り値の型を Any として宣言できます。

これにより、意図的に任意の値を返していることをエディタに伝えます。ただし、FastAPI は response_model を使用してデータのドキュメント化、検証、フィルタリングなどを引き続き行います。

response_model の優先順位

戻り値の型と response_model の両方を宣言した場合、response_model が優先され、FastAPI によって使用されます。

これにより、レスポンスモデルとは異なる型を返している場合でも、関数に正しい型アノテーションを追加して、エディタや mypy などのツールで使用することができます。また、response_model を使用して、FastAPI でデータの検証、ドキュメント化などを行うことができます。

また、response_model=None を使用して、その*パス操作*に対するレスポンスモデルの作成を無効にすることもできます。これは、有効な Pydantic フィールドではないものに型アノテーションを追加する場合に必要になることがあります。以下のセクションのいずれかでその例を示します。

同じ入力データを返す

ここでは、UserIn モデルを宣言しています。これは平文のパスワードを含みます。

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: str | None = None


# Don't do this in production!
@app.post("/user/")
async def create_user(user: UserIn) -> UserIn:
    return user
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: Union[str, None] = None


# Don't do this in production!
@app.post("/user/")
async def create_user(user: UserIn) -> UserIn:
    return user

情報

EmailStr を使用するには、最初に email-validator をインストールしてください。

仮想環境を作成し、アクティブ化してから、例えば次のようにインストールしてください。

$ pip install email-validator

または、次のようにインストールします。

$ pip install "pydantic[email]"

そして、このモデルを使用して入力を宣言し、同じモデルを使用して出力を宣言しています。

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: str | None = None


# Don't do this in production!
@app.post("/user/")
async def create_user(user: UserIn) -> UserIn:
    return user
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: Union[str, None] = None


# Don't do this in production!
@app.post("/user/")
async def create_user(user: UserIn) -> UserIn:
    return user

これで、ブラウザがパスワードを使用してユーザーを作成するたびに、API はレスポンスで同じパスワードを返します。

この場合、パスワードを送信しているのが同じユーザーであるため、問題にならない可能性があります。

しかし、別の*パス操作*に同じモデルを使用すると、ユーザーのパスワードをすべてのクライアントに送信してしまう可能性があります。

危険

すべての注意点と、自分が何をしているかを理解していない限り、ユーザーの平文パスワードを保存したり、このようにレスポンスで送信したりしないでください。

出力モデルを追加する

代わりに、平文パスワードを持つ入力モデルと、それを持たない出力モデルを作成することができます。

from typing import Any

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: str | None = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: str | None = None


@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn) -> Any:
    return user
from typing import Any, Union

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: Union[str, None] = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: Union[str, None] = None


@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn) -> Any:
    return user

ここでは、*パス操作関数*がパスワードを含む同じ入力ユーザーを返している場合でも

from typing import Any

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: str | None = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: str | None = None


@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn) -> Any:
    return user
from typing import Any, Union

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: Union[str, None] = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: Union[str, None] = None


@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn) -> Any:
    return user

...response_model をパスワードを含まない UserOut モデルとして宣言しました。

from typing import Any

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: str | None = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: str | None = None


@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn) -> Any:
    return user
from typing import Any, Union

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: Union[str, None] = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: Union[str, None] = None


@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn) -> Any:
    return user

そのため、**FastAPI** は出力モデルで宣言されていないすべてのデータをフィルタリングします(Pydantic を使用)。

response_model または戻り値の型

この場合、2 つのモデルが異なるため、関数の戻り値の型を UserOut としてアノテーション付けすると、エディタとツールは、異なるクラスであるため、無効な型を返していると警告します。

そのため、この例では、response_model パラメータで宣言する必要があります。

...しかし、これを克服する方法については、以下を読み続けてください。

戻り値の型とデータフィルタリング

前の例から続けましょう。関数を**1 つの型でアノテーション付け**したい一方で、関数から**より多くのデータ**を含むものを実際に返すことができるようにしたいと考えていました。

FastAPI がレスポンスモデルを使用してデータを**フィルタリング**し続けるようにしたいと考えています。そのため、関数がより多くのデータを返しても、レスポンスにはレスポンスモデルで宣言されたフィールドのみが含まれます。

前の例では、クラスが異なっていたため、response_model パラメータを使用する必要がありました。しかし、それはまた、エディタとツールのサポートが関数の戻り値の型チェックで得られないことを意味します。

しかし、このようなことをする必要がある場合のほとんどは、この例のように、モデルにデータの一部を**フィルタリング/削除**させたいだけです。

そして、そのような場合、クラスと継承を使用して関数の**型アノテーション**を活用することで、エディタとツールでより良いサポートを得ることができ、さらに FastAPI の**データフィルタリング**も得ることができます。

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class BaseUser(BaseModel):
    username: str
    email: EmailStr
    full_name: str | None = None


class UserIn(BaseUser):
    password: str


@app.post("/user/")
async def create_user(user: UserIn) -> BaseUser:
    return user
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class BaseUser(BaseModel):
    username: str
    email: EmailStr
    full_name: Union[str, None] = None


class UserIn(BaseUser):
    password: str


@app.post("/user/")
async def create_user(user: UserIn) -> BaseUser:
    return user

これにより、このコードは型の観点から正しいので、エディタと mypy からのツールサポートが得られますが、FastAPI からのデータフィルタリングも得られます。

これはどのように機能するのでしょうか?見てみましょう。🤓

型アノテーションとツール

最初に、エディタ、mypy、その他のツールがこれをどのように認識するかを見てみましょう。

BaseUser には基本フィールドがあります。次に、UserInBaseUser から継承し、password フィールドを追加するため、両方のモデルのすべてのフィールドが含まれます。

関数の戻り値の型を BaseUser としてアノテーション付けしていますが、実際には UserIn インスタンスを返しています。

エディタ、mypy、およびその他のツールは、これについて文句を言いません。なぜなら、タイピングの観点から、UserInBaseUser のサブクラスであり、これは BaseUser であるものが期待されている場合に*有効な*型であることを意味するからです。

FastAPI データフィルタリング

さて、FastAPI の場合、戻り値の型を確認し、返されるものが型で宣言されているフィールド**のみ**を含むことを確認します。

FastAPI は Pydantic を使用して内部でいくつかのことを行い、クラス継承の同じルールが返されるデータフィルタリングに使用されないようにします。そうでない場合、予期したよりもはるかに多くのデータを返す可能性があります。

このようにして、**ツールサポート**と**データフィルタリング**という両方の利点を得ることができます。

ドキュメントで確認する

自動ドキュメントを見ると、入力モデルと出力モデルの両方に独自の JSON スキーマがあることを確認できます。

そして、両方のモデルがインタラクティブ API ドキュメントに使用されます。

その他の戻り値の型アノテーション

有効な Pydantic フィールドではないものを返し、ツール(エディタ、mypy など)によって提供されるサポートを得るためだけに、関数でアノテーションを付ける場合があります。

レスポンスを直接返す

最も一般的なケースは、高度なドキュメントで後述するように、レスポンスを直接返すことです。

from fastapi import FastAPI, Response
from fastapi.responses import JSONResponse, RedirectResponse

app = FastAPI()


@app.get("/portal")
async def get_portal(teleport: bool = False) -> Response:
    if teleport:
        return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
    return JSONResponse(content={"message": "Here's your interdimensional portal."})

この単純なケースは、戻り値の型アノテーションが Response クラス(またはそのサブクラス)であるため、FastAPI によって自動的に処理されます。

また、RedirectResponseJSONResponse はどちらも Response のサブクラスであるため、型アノテーションは正しいので、ツールも問題ありません。

レスポンスサブクラスにアノテーションを付ける

型アノテーションで Response のサブクラスを使用することもできます。

from fastapi import FastAPI
from fastapi.responses import RedirectResponse

app = FastAPI()


@app.get("/teleport")
async def get_teleport() -> RedirectResponse:
    return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")

RedirectResponseResponse のサブクラスであるため、これも機能し、FastAPI はこの単純なケースを自動的に処理します。

無効な戻り値の型アノテーション

しかし、有効な Pydantic 型ではない任意のオブジェクト(例:データベースオブジェクト)を返し、関数でそのようにアノテーションを付けると、FastAPI はその型アノテーションから Pydantic レスポンスモデルを作成しようとしますが、失敗します。

1 つ以上の型が有効な Pydantic 型ではない異なる型間のユニオンがある場合も同様で、たとえば、これは失敗します 💥

from fastapi import FastAPI, Response
from fastapi.responses import RedirectResponse

app = FastAPI()


@app.get("/portal")
async def get_portal(teleport: bool = False) -> Response | dict:
    if teleport:
        return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
    return {"message": "Here's your interdimensional portal."}
from typing import Union

from fastapi import FastAPI, Response
from fastapi.responses import RedirectResponse

app = FastAPI()


@app.get("/portal")
async def get_portal(teleport: bool = False) -> Union[Response, dict]:
    if teleport:
        return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
    return {"message": "Here's your interdimensional portal."}

...これは、型アノテーションが Pydantic 型ではなく、単一の Response クラスまたはサブクラスではなく、Responsedict 間のユニオン(2 つのいずれか)であるため失敗します。

レスポンスモデルを無効にする

上記の例を続けると、FastAPI によって実行されるデフォルトのデータ検証、ドキュメント化、フィルタリングなどを行いたくない場合があります。

しかし、エディタや型チェッカー(例:mypy)からのサポートを得るために、関数に戻り値の型アノテーションを保持したい場合があります。

この場合、response_model=None を設定することで、レスポンスモデルの生成を無効にすることができます。

from fastapi import FastAPI, Response
from fastapi.responses import RedirectResponse

app = FastAPI()


@app.get("/portal", response_model=None)
async def get_portal(teleport: bool = False) -> Response | dict:
    if teleport:
        return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
    return {"message": "Here's your interdimensional portal."}
from typing import Union

from fastapi import FastAPI, Response
from fastapi.responses import RedirectResponse

app = FastAPI()


@app.get("/portal", response_model=None)
async def get_portal(teleport: bool = False) -> Union[Response, dict]:
    if teleport:
        return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
    return {"message": "Here's your interdimensional portal."}

これにより、FastAPI はレスポンスモデルの生成をスキップし、FastAPI アプリケーションに影響を与えることなく、必要な戻り値の型アノテーションを持つことができます。🤓

レスポンスモデルのエンコーディングパラメータ

レスポンスモデルには、次のようなデフォルト値を設定できます。

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float = 10.5
    tags: list[str] = []


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
    return items[item_id]
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: float = 10.5
    tags: list[str] = []


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
    return items[item_id]
from typing import List, Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


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


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
    return items[item_id]
  • description: Union[str, None] = None(または Python 3.10 では str | None = None)は、デフォルトで None です。
  • tax: float = 10.5 は、デフォルトで 10.5 です。
  • tags: List[str] = [] は、デフォルトで空のリスト:[] です。

しかし、実際に保存されていない場合は、結果から省略したい場合があります。

たとえば、NoSQL データベースに多くのオプション属性を持つモデルがあるが、デフォルト値でいっぱいの非常に長い JSON レスポンスを送信したくない場合などです。

response_model_exclude_unset パラメータを使用する

*パス操作デコレータ*パラメータ response_model_exclude_unset=True を設定できます。

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float = 10.5
    tags: list[str] = []


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
    return items[item_id]
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: float = 10.5
    tags: list[str] = []


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
    return items[item_id]
from typing import List, Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


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


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
    return items[item_id]

これらのデフォルト値はレスポンスに含まれず、実際に設定された値のみが含まれます。

そのため、ID が foo のアイテムに対してその*パス操作*にリクエストを送信すると、レスポンス(デフォルト値は含まない)は次のようになります。

{
    "name": "Foo",
    "price": 50.2
}

情報

Pydantic v1 では、メソッドは .dict() と呼ばれていましたが、Pydantic v2 では非推奨(ただし、まだサポートされています)となり、.model_dump() に名前が変更されました。

ここでの例では、Pydantic v1 との互換性のために .dict() を使用していますが、Pydantic v2 を使用できる場合は、代わりに .model_dump() を使用する必要があります。

情報

FastAPI は、exclude_unset パラメータを持つ Pydantic モデルの .dict() を使用してこれを実現します。

情報

また、次のように使用することもできます。

  • response_model_exclude_defaults=True
  • response_model_exclude_none=True

Pydantic のドキュメントexclude_defaultsexclude_none について説明されているとおりです。

デフォルト値を持つフィールドの値を持つデータ

しかし、ID が `bar` のアイテムのように、データにデフォルト値を持つモデルのフィールドの値がある場合

{
    "name": "Bar",
    "description": "The bartenders",
    "price": 62,
    "tax": 20.2
}

それらはレスポンスに含まれます。

デフォルトと同じ値を持つデータ

ID が `baz` のアイテムのように、データにデフォルトと同じ値がある場合

{
    "name": "Baz",
    "description": None,
    "price": 50.2,
    "tax": 10.5,
    "tags": []
}

FastAPI は(実際には、Pydantic は)descriptiontax、および tags がデフォルトと同じ値であっても、それらが明示的に設定されている(デフォルトから取得されたのではなく)ことを認識するのに十分賢いです。

そのため、JSON レスポンスに含まれます。

ヒント

デフォルト値は None だけではなく、何でもかまいません。

リスト([])、10.5float などにすることができます。

response_model_includeresponse_model_exclude

パス操作デコレータのパラメータ `response_model_include` と `response_model_exclude` を使用することもできます。

これらは、含める属性の名前(残りは省略)または除外する属性の名前(残りは含む)を持つ `str` の `set` を取ります。

Pydanticモデルが1つだけで、出力からいくつかのデータを削除したい場合、これは簡単なショートカットとして使用できます。

ヒント

しかし、これらのパラメータの代わりに、上記のように複数のクラスを使用することをお勧めします。

これは、`response_model_include` または `response_model_exclude` を使用して一部の属性を省略した場合でも、アプリケーションのOpenAPI(およびドキュメント)で生成されるJSONスキーマは、完全なモデルのスキーマのままになるためです。

これは、同様に機能する `response_model_by_alias` にも当てはまります。

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


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


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2},
    "baz": {
        "name": "Baz",
        "description": "There goes my baz",
        "price": 50.2,
        "tax": 10.5,
    },
}


@app.get(
    "/items/{item_id}/name",
    response_model=Item,
    response_model_include={"name", "description"},
)
async def read_item_name(item_id: str):
    return items[item_id]


@app.get("/items/{item_id}/public", response_model=Item, response_model_exclude={"tax"})
async def read_item_public_data(item_id: str):
    return items[item_id]
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: float = 10.5


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2},
    "baz": {
        "name": "Baz",
        "description": "There goes my baz",
        "price": 50.2,
        "tax": 10.5,
    },
}


@app.get(
    "/items/{item_id}/name",
    response_model=Item,
    response_model_include={"name", "description"},
)
async def read_item_name(item_id: str):
    return items[item_id]


@app.get("/items/{item_id}/public", response_model=Item, response_model_exclude={"tax"})
async def read_item_public_data(item_id: str):
    return items[item_id]

ヒント

`{"name", "description"}` という構文は、これらの2つの値を持つ `set` を作成します。

これは `set(["name", "description"])` と同等です。

`set` の代わりに `list` を使用する場合

`set` を使用することを忘れて、代わりに `list` または `tuple` を使用した場合でも、FastAPIはそれを `set` に変換するため、正しく動作します。

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


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


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2},
    "baz": {
        "name": "Baz",
        "description": "There goes my baz",
        "price": 50.2,
        "tax": 10.5,
    },
}


@app.get(
    "/items/{item_id}/name",
    response_model=Item,
    response_model_include=["name", "description"],
)
async def read_item_name(item_id: str):
    return items[item_id]


@app.get("/items/{item_id}/public", response_model=Item, response_model_exclude=["tax"])
async def read_item_public_data(item_id: str):
    return items[item_id]
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: float = 10.5


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2},
    "baz": {
        "name": "Baz",
        "description": "There goes my baz",
        "price": 50.2,
        "tax": 10.5,
    },
}


@app.get(
    "/items/{item_id}/name",
    response_model=Item,
    response_model_include=["name", "description"],
)
async def read_item_name(item_id: str):
    return items[item_id]


@app.get("/items/{item_id}/public", response_model=Item, response_model_exclude=["tax"])
async def read_item_public_data(item_id: str):
    return items[item_id]

まとめ

レスポンスモデルを定義し、特にプライベートデータが除外されるようにするには、*パス操作デコレータ*のパラメータ `response_model` を使用します。

明示的に設定された値のみを返すには、`response_model_exclude_unset` を使用します。