直接返回响应¶
当你创建一个 FastAPI 路径操作 时,通常可以返回任何数据:dict、list、Pydantic 模型、数据库模型等。
如果你声明了一个 响应模型 (Response Model),FastAPI 将使用 Pydantic 将数据序列化为 JSON。
如果你没有声明响应模型,FastAPI 将使用在 JSON 兼容编码器 中介绍的 jsonable_encoder,并将其放入 JSONResponse 中。
你也可以直接创建一个 JSONResponse 并返回它。
提示
通常情况下,使用 响应模型 (Response Model) 会比直接返回 JSONResponse 获得更好的性能,因为前者使用 Rust 编写的 Pydantic 来序列化数据。
返回一个 Response¶
你可以返回一个 Response 或其任何子类。
注意
JSONResponse 本身就是 Response 的一个子类。
当你返回一个 Response 时,FastAPI 将会直接将其传递出去。
它不会使用 Pydantic 模型进行任何数据转换,也不会将内容转换为任何类型等。
这赋予了你极大的灵活性。你可以返回任何数据类型,覆盖任何数据声明或验证等。
同时也赋予了你很大的责任。你必须确保返回的数据是正确的、格式正确的、可序列化的等等。
在 Response 中使用 jsonable_encoder¶
由于 FastAPI 不会对你返回的 Response 进行任何修改,你必须确保其内容已经准备就绪。
例如,如果不先将其转换为 dict,并将所有数据类型(如 datetime、UUID 等)转换为 JSON 兼容类型,你就不能将 Pydantic 模型放入 JSONResponse 中。
在这种情况下,你可以使用 jsonable_encoder 在将数据传递给响应之前对其进行转换。
from datetime import datetime
from fastapi import FastAPI
from fastapi.encoders import jsonable_encoder
from fastapi.responses import JSONResponse
from pydantic import BaseModel
class Item(BaseModel):
title: str
timestamp: datetime
description: str | None = None
app = FastAPI()
@app.put("/items/{id}")
def update_item(id: str, item: Item):
json_compatible_item_data = jsonable_encoder(item)
return JSONResponse(content=json_compatible_item_data)
技术细节
你也可以使用 from starlette.responses import JSONResponse。
FastAPI 提供与 fastapi.responses 相同的 starlette.responses 只是为了方便开发者。但大多数可用的响应直接来自 Starlette。
返回自定义 Response¶
上面的示例展示了你需要的所有部分,但它还不是很有用,因为你本可以直接返回 item,FastAPI 会为你将其放入 JSONResponse 中,并自动将其转换为 dict 等。所有这些都是默认行为。
现在,让我们看看如何利用这一点来返回自定义响应。
假设你想返回一个 XML 响应。
你可以将 XML 内容放入字符串,放入 Response 中,然后返回它。
from fastapi import FastAPI, Response
app = FastAPI()
@app.get("/legacy/")
def get_legacy_data():
data = """<?xml version="1.0"?>
<shampoo>
<Header>
Apply shampoo here.
</Header>
<Body>
You'll have to use soap here.
</Body>
</shampoo>
"""
return Response(content=data, media_type="application/xml")
响应模型的工作原理¶
当你在路径操作中声明 响应模型 - 返回类型 时,FastAPI 将使用它通过 Pydantic 将数据序列化为 JSON。
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),
]
由于这一过程是在 Rust 端完成的,其性能将远高于使用普通 Python 和 JSONResponse 类的情况。
当使用 response_model 或返回类型时,FastAPI 不会使用 jsonable_encoder 来转换数据(那样会更慢),也不会使用 JSONResponse 类。
相反,它会直接采用使用响应模型(或返回类型)通过 Pydantic 生成的 JSON 字节,并返回一个具有正确 JSON 媒体类型(application/json)的 Response。
注意事项¶
当你直接返回一个 Response 时,其数据不会被自动验证、转换(序列化)或文档化。
但你仍然可以按照 OpenAPI 中的额外响应 所述对其进行文档化。
你可以在后面的章节中看到如何使用/声明这些自定义的 Response,同时仍然保持自动数据转换、文档化等功能。