コンテンツにスキップ

OpenAPIにおける追加レスポンス

警告

これはかなり高度なトピックです。

FastAPIを使い始めたばかりの場合、これは必要ないかもしれません。

追加のステータスコード、メディアタイプ、説明などを使用して、追加のレスポンスを宣言できます。

これらの追加レスポンスはOpenAPIスキーマに含まれるため、APIドキュメントにも表示されます。

ただし、これらの追加レスポンスについては、ステータスコードとコンテンツを含むJSONResponseのようなResponseを直接返すようにする必要があります。

modelを使った追加レスポンス

パス操作デコレータresponsesパラメータを渡すことができます。

これはdictを受け取ります。キーは各レスポンスのステータスコード(200など)、値はそれぞれの情報を持つ別のdictです。

これらのレスポンスdictにはそれぞれ、response_modelと同様に、Pydanticモデルを含むmodelキーを含めることができます。

FastAPIはそのモデルを取得し、そのJSONスキーマを生成して、OpenAPIの適切な場所に含めます。

たとえば、ステータスコード404とPydanticモデルMessageを持つ別のレスポンスを宣言するには、次のように記述できます。

from fastapi import FastAPI
from fastapi.responses import JSONResponse
from pydantic import BaseModel


class Item(BaseModel):
    id: str
    value: str


class Message(BaseModel):
    message: str


app = FastAPI()


@app.get("/items/{item_id}", response_model=Item, responses={404: {"model": Message}})
async def read_item(item_id: str):
    if item_id == "foo":
        return {"id": "foo", "value": "there goes my hero"}
    return JSONResponse(status_code=404, content={"message": "Item not found"})

注意

JSONResponseを直接返す必要があることに注意してください。

情報

modelキーはOpenAPIの一部ではありません。

FastAPIはそこからPydanticモデルを取得し、JSONスキーマを生成して、適切な場所に配置します。

適切な場所は次のとおりです。

  • 値として別のJSONオブジェクト(dict)を持つcontentキーに。
    • メディアタイプ(例:application/json)を持つキー。値として、別のJSONオブジェクトを持つ。
      • キーschema。値としてモデルからのJSONスキーマがあります。ここが正しい場所です。
        • FastAPIは、直接含める代わりに、ここでOpenAPI内の別の場所にあるグローバルJSONスキーマへの参照を追加します。これにより、他のアプリケーションやクライアントはこれらのJSONスキーマを直接使用でき、より優れたコード生成ツールなどを提供できます。

このパス操作のOpenAPIで生成されるレスポンスは次のようになります。

{
    "responses": {
        "404": {
            "description": "Additional Response",
            "content": {
                "application/json": {
                    "schema": {
                        "$ref": "#/components/schemas/Message"
                    }
                }
            }
        },
        "200": {
            "description": "Successful Response",
            "content": {
                "application/json": {
                    "schema": {
                        "$ref": "#/components/schemas/Item"
                    }
                }
            }
        },
        "422": {
            "description": "Validation Error",
            "content": {
                "application/json": {
                    "schema": {
                        "$ref": "#/components/schemas/HTTPValidationError"
                    }
                }
            }
        }
    }
}

スキーマはOpenAPIスキーマ内の別の場所に参照されます。

{
    "components": {
        "schemas": {
            "Message": {
                "title": "Message",
                "required": [
                    "message"
                ],
                "type": "object",
                "properties": {
                    "message": {
                        "title": "Message",
                        "type": "string"
                    }
                }
            },
            "Item": {
                "title": "Item",
                "required": [
                    "id",
                    "value"
                ],
                "type": "object",
                "properties": {
                    "id": {
                        "title": "Id",
                        "type": "string"
                    },
                    "value": {
                        "title": "Value",
                        "type": "string"
                    }
                }
            },
            "ValidationError": {
                "title": "ValidationError",
                "required": [
                    "loc",
                    "msg",
                    "type"
                ],
                "type": "object",
                "properties": {
                    "loc": {
                        "title": "Location",
                        "type": "array",
                        "items": {
                            "type": "string"
                        }
                    },
                    "msg": {
                        "title": "Message",
                        "type": "string"
                    },
                    "type": {
                        "title": "Error Type",
                        "type": "string"
                    }
                }
            },
            "HTTPValidationError": {
                "title": "HTTPValidationError",
                "type": "object",
                "properties": {
                    "detail": {
                        "title": "Detail",
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/ValidationError"
                        }
                    }
                }
            }
        }
    }
}

メインレスポンスの追加メディアタイプ

この同じresponsesパラメータを使用して、同じメインレスポンスに対して異なるメディアタイプを追加できます。

たとえば、パス操作がJSONオブジェクト(メディアタイプapplication/json)またはPNG画像を返すことができると宣言することで、image/pngの追加メディアタイプを追加できます。

from typing import Union

from fastapi import FastAPI
from fastapi.responses import FileResponse
from pydantic import BaseModel


class Item(BaseModel):
    id: str
    value: str


app = FastAPI()


@app.get(
    "/items/{item_id}",
    response_model=Item,
    responses={
        200: {
            "content": {"image/png": {}},
            "description": "Return the JSON item or an image.",
        }
    },
)
async def read_item(item_id: str, img: Union[bool, None] = None):
    if img:
        return FileResponse("image.png", media_type="image/png")
    else:
        return {"id": "foo", "value": "there goes my hero"}

注意

FileResponseを直接使用して画像を返す必要があることに注意してください。

情報

responsesパラメータで別のメディアタイプを明示的に指定しない限り、FastAPIは、レスポンスがメインレスポンスクラス(デフォルトapplication/json)と同じメディアタイプを持つと想定します。

ただし、メディアタイプとしてNoneを持つカスタムレスポンスクラスを指定した場合、FastAPIは、関連付けられたモデルを持つ追加レスポンスにapplication/jsonを使用します。

情報の組み合わせ

response_modelstatus_coderesponsesパラメータを含む、複数の場所からのレスポンス情報を組み合わせることもできます。

デフォルトのステータスコード200(または必要に応じてカスタムのステータスコード)を使用してresponse_modelを宣言し、responsesでその同じレスポンスの追加情報をOpenAPIスキーマに直接宣言できます。

FastAPIは、responsesからの追加情報を保持し、モデルからのJSONスキーマと組み合わせます。

たとえば、Pydanticモデルを使用し、カスタムのdescriptionを持つステータスコード404を持つレスポンスを宣言できます。

また、response_modelを使用するが、カスタムのexampleを含むステータスコード200を持つレスポンスを宣言できます。

from fastapi import FastAPI
from fastapi.responses import JSONResponse
from pydantic import BaseModel


class Item(BaseModel):
    id: str
    value: str


class Message(BaseModel):
    message: str


app = FastAPI()


@app.get(
    "/items/{item_id}",
    response_model=Item,
    responses={
        404: {"model": Message, "description": "The item was not found"},
        200: {
            "description": "Item requested by ID",
            "content": {
                "application/json": {
                    "example": {"id": "bar", "value": "The bar tenders"}
                }
            },
        },
    },
)
async def read_item(item_id: str):
    if item_id == "foo":
        return {"id": "foo", "value": "there goes my hero"}
    else:
        return JSONResponse(status_code=404, content={"message": "Item not found"})

これらはすべて結合され、あなたのOpenAPIに含められ、APIドキュメントに表示されます。

事前定義されたレスポンスとカスタムレスポンスを組み合わせる

多くのパスオペレーションに適用できる事前定義されたレスポンスを持ちたいが、各パスオペレーションに必要なカスタムレスポンスと組み合わせたい場合があります。

そのような場合、Pythonのテクニックである**dict_to_unpackdictを「展開」することができます。

old_dict = {
    "old key": "old value",
    "second old key": "second old value",
}
new_dict = {**old_dict, "new key": "new value"}

ここで、new_dictには、old_dictのすべてのキーと値のペアと、新しいキーと値のペアが含まれます。

{
    "old key": "old value",
    "second old key": "second old value",
    "new key": "new value",
}

このテクニックを使用すると、パスオペレーションでいくつかの事前定義されたレスポンスを再利用し、追加のカスタムレスポンスと組み合わせることができます。

例:

from typing import Union

from fastapi import FastAPI
from fastapi.responses import FileResponse
from pydantic import BaseModel


class Item(BaseModel):
    id: str
    value: str


responses = {
    404: {"description": "Item not found"},
    302: {"description": "The item was moved"},
    403: {"description": "Not enough privileges"},
}


app = FastAPI()


@app.get(
    "/items/{item_id}",
    response_model=Item,
    responses={**responses, 200: {"content": {"image/png": {}}}},
)
async def read_item(item_id: str, img: Union[bool, None] = None):
    if img:
        return FileResponse("image.png", media_type="image/png")
    else:
        return {"id": "foo", "value": "there goes my hero"}

OpenAPIレスポンスに関する詳細情報

レスポンスに含めることができる内容を正確に確認するには、OpenAPI仕様の次のセクションを確認してください。

  • OpenAPI Responses Object には、Response Objectが含まれています。
  • OpenAPI Response Object では、responsesパラメータ内の各レスポンスに、descriptionheaderscontent(この中では、さまざまなメディアタイプとJSONスキーマを宣言します)、およびlinksなど、ここから直接含めることができます。