跳转至

OpenAPI 中的附加响应

警告

本章较难。

FastAPI 新手可跳过本章。

本章学习使用附加状态码、媒体类型、描述等声明响应。

这些响应会包含在 OpenAPI 概图里,并在 API 文档中显示。

但必须要确保这些响应与状态码和 content 一起直接以 JSONResponse 等方式返回。

使用 model 的响应

路径操作装饰器支持 response 参数。

response 参数可以接收键是响应的状态码,如 200,值是响应信息的字典。

响应字典可以包含 Pydantic 模型的键 model,如 response_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 Schema,并把它推送到正确的位置。

正确的位置是:

  • content 键中的 JSON 对象(字典),该对象包含:
    • 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"
                        }
                    }
                }
            }
        }
    }
}

主响应的附加媒体类型

response 参数还可以为主响应添加媒体类型。

例如,添加 image/png 媒体类型,声明返回 JSON 对象(使用 application/json)或 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 返回图像。

说明

除非在 response 参数中显式指定其他媒体类型,否则,FastAPI 假设该响应和主响应类的媒体类型一样(默认为 application/json)。

使用 None 指定自定义响应类的媒体类型时,FastAPI 会为包含关联模型的响应使用 application/json

合并信息

FastAPI 支持合并 response_modelstatus_coderesponses 参数等多个位置的响应信息。

使用默认状态码 200(或自定义状态码),声明 response_model。然后,直接在 OpenAPI 概图中,为 responses 中的同一响应声明更多信息。

FastAPI 保留 responses 中的信息,并把它与模型的 JSON 概图合并在一起。

例如,使用 Pydantic 模型声明包含状态码 404 的响应,并包含自定义 description

带状态码 200 的响应不仅使用 response_model,还包含了自定义 example

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 文档中显示:

合并预定义响应与自定义响应

FastAPI 还可以合并路径操作中的预定义响应和自定义响应。

此处使用 Python 字典解包,即 **dict_to_unpack

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 规范的相关章节: