OpenAPI 中的额外响应¶
警告
这是一个比较高级的主题。
如果您刚开始接触 FastAPI,可能暂时用不到它。
您可以声明带有额外状态码、媒体类型、描述等的额外响应。
这些额外响应将被包含在 OpenAPI 模式(schema)中,因此它们也会显示在 API 文档中。
但对于这些额外响应,您必须确保直接返回一个 Response 对象(如 JSONResponse),并指定您的状态码和内容。
带有 model 的额外响应¶
您可以向路径操作装饰器传入一个 responses 参数。
它接收一个 dict:键是每个响应的状态码(如 200),值是包含每个响应信息的另一个 dict。
这些响应 dict 中的每一个都可以包含一个 model 键,其中包含一个 Pydantic 模型,就像 response_model 一样。
FastAPI 会获取该模型,生成其 JSON Schema,并将其包含在 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 对象(dict),其中包含:- 一个以媒体类型为键(例如
application/json)的条目,其值是另一个 JSON 对象,其中包含:- 一个
schema键,其值就是来自模型的 JSON Schema,这就是正确的位置。- FastAPI 会在此处添加一个对 OpenAPI 中其他位置的全局 JSON Schema 的引用,而不是直接包含它。这样,其他应用程序和客户端可以直接使用这些 JSON Schema,提供更好的代码生成工具等。
- 一个
- 一个以媒体类型为键(例如
该路径操作在 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 参数为同一个主响应添加不同的媒体类型。
例如,您可以添加一个 image/png 的额外媒体类型,声明您的路径操作可以返回一个 JSON 对象(媒体类型为 application/json)或者一个 PNG 图像:
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: 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_model、status_code 和 responses 参数。
您可以使用默认状态码 200(或者根据需要自定义状态码)声明 response_model,然后在 responses 中直接在 OpenAPI 模式中为同一个响应声明额外信息。
FastAPI 将保留 responses 中的额外信息,并将其与来自您模型的 JSON Schema 相结合。
例如,您可以声明一个状态码为 404 的响应,它使用 Pydantic 模型并具有自定义的 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 文档中显示出来。

结合预定义响应与自定义响应¶
您可能希望拥有一些适用于多个路径操作的预定义响应,但又想将它们与每个路径操作所需的自定义响应结合起来。
在这种情况下,您可以使用 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 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: 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参数的每个响应中包含此对象中的任何内容。包括description、headers、content(您可以在此声明不同的媒体类型和 JSON Schema)以及links。