OpenAPI 中的額外回應¶
警告
這是一個偏進階的主題。
如果你剛開始使用 FastAPI,大多情況下不需要用到它。
你可以宣告額外的回應,包含額外的狀態碼、媒體型別、描述等。
這些額外回應會被包含在 OpenAPI 中,因此也會顯示在 API 文件裡。
但對於這些額外回應,你必須直接回傳像 JSONResponse 這樣的 Response,並包含你的狀態碼與內容。
使用 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 Schemas 的參照,而不是直接把它嵌入。如此一來,其他應用與用戶端可以直接使用那些 JSON Schemas,提供更好的程式碼產生工具等。
- 鍵
- 一個媒體型別作為鍵,例如
這個路徑操作在 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"
}
}
}
}
}
}
這些 Schemas 會在 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 參數。
你可以宣告一個 response_model,使用預設狀態碼 200(或你需要的自訂狀態碼),然後在 responses 中直接於 OpenAPI Schema 為相同的回應宣告額外資訊。
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 技巧,透過 **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 物件,其中包含
Response Object。 - OpenAPI Response 物件,你可以把這裡的任何內容直接放到
responses參數內各個回應中。包含description、headers、content(在其中宣告不同的媒體型別與 JSON Schemas)、以及links。