跳转至

请求体

当你需要将数据从客户端(例如浏览器)发送到 API 时,你可以将其作为请求体发送。

请求体是客户端发送到 API 的数据。响应体是 API 发送到客户端的数据。

你的 API 几乎总是需要发送一个响应体。但客户端并不总是需要发送请求体,有时它们只请求一个路径,可能带有一些查询参数,但不发送请求体。

要声明一个请求体,你可以使用 Pydantic 模型,并利用其所有功能和优势。

Info

要发送数据,你应该使用以下方法之一:POST(更常见)、PUTDELETEPATCH

在规范中,使用 GET 请求发送请求体的行为是未定义的,但 FastAPI 支持它,仅适用于非常复杂/极端的用例。

由于不鼓励这样做,使用 Swagger UI 的交互式文档在使用 GET 时不会显示请求体的文档,并且中间的代理可能不支持它。

导入 Pydantic 的 BaseModel

首先,你需要从 pydantic 导入 BaseModel

from fastapi import FastAPI
from pydantic import BaseModel


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


app = FastAPI()


@app.post("/items/")
async def create_item(item: Item):
    return item
🤓 Other versions and variants
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None


app = FastAPI()


@app.post("/items/")
async def create_item(item: Item):
    return item

创建你的数据模型

然后,你将数据模型声明为一个继承自 BaseModel 的类。

对所有属性使用标准的 Python 类型:

from fastapi import FastAPI
from pydantic import BaseModel


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


app = FastAPI()


@app.post("/items/")
async def create_item(item: Item):
    return item
🤓 Other versions and variants
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None


app = FastAPI()


@app.post("/items/")
async def create_item(item: Item):
    return item

与声明查询参数时相同,当模型属性具有默认值时,它不是必需的。否则,它是必需的。使用 None 使其成为可选项。

例如,上面的模型声明了一个 JSON "object"(或 Python dict),如下所示:

{
    "name": "Foo",
    "description": "An optional description",
    "price": 45.2,
    "tax": 3.5
}

...由于 descriptiontax 是可选的(默认值为 None),以下 JSON "object" 也是有效的:

{
    "name": "Foo",
    "price": 45.2
}

将其声明为参数

要将其添加到你的路径操作中,请以与声明路径和查询参数相同的方式声明它:

from fastapi import FastAPI
from pydantic import BaseModel


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


app = FastAPI()


@app.post("/items/")
async def create_item(item: Item):
    return item
🤓 Other versions and variants
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None


app = FastAPI()


@app.post("/items/")
async def create_item(item: Item):
    return item

...并将其类型声明为你创建的模型 Item

结果

仅通过该 Python 类型声明,FastAPI 将:

  • 以 JSON 格式读取请求体。
  • 转换相应的类型(如果需要)。
  • 验证数据。
    • 如果数据无效,它将返回一个清晰明了的错误,准确指出不正确数据的位置和内容。
  • 在参数 item 中提供接收到的数据。
    • 由于你在函数中声明其类型为 Item,你还将获得所有属性和其类型的编辑器支持(自动完成等)。
  • 为你的模型生成 JSON Schema 定义,你也可以在项目中有意义的任何其他地方使用它们。
  • 这些模式将成为生成的 OpenAPI 模式的一部分,并被自动文档 UI 使用。

自动文档

你的模型的 JSON 模式将成为生成的 OpenAPI 模式的一部分,并显示在交互式 API 文档中:

并且还将在每个需要它们的路径操作的 API 文档中使用:

编辑器支持

在你的编辑器中,在函数内部你将在各处获得类型提示和自动完成(如果你接收的是 dict 而不是 Pydantic 模型,则不会发生这种情况):

你还会获得对不正确类型操作的错误检查:

这不是偶然的,整个框架都是围绕该设计构建的。

并且在设计阶段进行了全面测试,确保它能与所有编辑器一起工作,然后才进行实现。

甚至对 Pydantic 本身进行了一些更改以支持此功能。

之前的截图是使用 Visual Studio Code 拍摄的。

但你在 PyCharm 和大多数其他 Python 编辑器中也会获得相同的编辑器支持:

Tip

如果你使用 PyCharm 作为编辑器,你可以使用 Pydantic PyCharm Plugin

它通过以下方式改进了对 Pydantic 模型的编辑器支持:

  • 自动完成
  • 类型检查
  • 重构
  • 搜索
  • 检查

使用模型

在函数内部,你可以直接访问模型对象的所有属性:

from fastapi import FastAPI
from pydantic import BaseModel


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


app = FastAPI()


@app.post("/items/")
async def create_item(item: Item):
    item_dict = item.dict()
    if item.tax is not None:
        price_with_tax = item.price + item.tax
        item_dict.update({"price_with_tax": price_with_tax})
    return item_dict
🤓 Other versions and variants
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None


app = FastAPI()


@app.post("/items/")
async def create_item(item: Item):
    item_dict = item.dict()
    if item.tax is not None:
        price_with_tax = item.price + item.tax
        item_dict.update({"price_with_tax": price_with_tax})
    return item_dict

Info

在 Pydantic v1 中,该方法称为 .dict(),在 Pydantic v2 中已弃用(但仍受支持),并重命名为 .model_dump()

此处的示例使用 .dict() 以与 Pydantic v1 兼容,但如果你可以使用 Pydantic v2,则应使用 .model_dump()

请求体 + 路径参数

你可以同时声明路径参数和请求体。

FastAPI 将识别与路径参数匹配的函数参数应从路径中获取,而声明为 Pydantic 模型的函数参数应从请求体中获取

from fastapi import FastAPI
from pydantic import BaseModel


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


app = FastAPI()


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    return {"item_id": item_id, **item.dict()}
🤓 Other versions and variants
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None


app = FastAPI()


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    return {"item_id": item_id, **item.dict()}

请求体 + 路径 + 查询参数

你还可以同时声明请求体路径查询参数。

FastAPI 将识别每个参数并从正确的位置获取数据。

from fastapi import FastAPI
from pydantic import BaseModel


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


app = FastAPI()


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item, q: str | None = None):
    result = {"item_id": item_id, **item.dict()}
    if q:
        result.update({"q": q})
    return result
🤓 Other versions and variants
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None


app = FastAPI()


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item, q: Union[str, None] = None):
    result = {"item_id": item_id, **item.dict()}
    if q:
        result.update({"q": q})
    return result

函数参数将被识别如下:

  • 如果参数也在路径中声明,它将被用作路径参数。
  • 如果参数是单一类型(如 intfloatstrbool 等),它将被解释为查询参数。
  • 如果参数被声明为Pydantic 模型的类型,它将被解释为请求

Note

FastAPI 将知道 q 的值不是必需的,因为默认值为 = None

str | None(Python 3.10+)或 Union 中的 Union[str, None](Python 3.8+)不被 FastAPI 用于确定该值不是必需的,它将知道它不是必需的,因为它具有默认值 = None

但添加类型注释将使你的编辑器能够提供更好的支持并检测错误。

不使用 Pydantic

如果你不想使用 Pydantic 模型,你也可以使用 Body 参数。请参阅 Body - Multiple Parameters: Singular values in body 的文档。