请求体¶
当你需要将数据从客户端(例如,浏览器)发送到你的 API 时,你将它作为请求体发送。
请求体是客户端发送给你的 API 的数据。响应体是你的 API 发送给客户端的数据。
你的 API 几乎总是需要发送响应体。但客户端不一定总是需要发送请求体,有时它们只请求一个路径,可能带有一些查询参数,但不发送请求体。
要声明请求体,你可以使用 Pydantic 模型,并享受它们所有的强大功能和优势。
信息
要发送请求体,你应该使用以下方法之一:POST
(最常见)、PUT
、DELETE
或 PATCH
。
在规范中,使用 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
🤓 其他版本和变体
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
🤓 其他版本和变体
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
}
...由于 description
和 tax
是可选的(默认值为 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
🤓 其他版本和变体
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 模式的一部分,并被自动文档 UIs 使用。
自动文档¶
你模型的 JSON Schema 将成为你生成的 OpenAPI 模式的一部分,并会显示在交互式 API 文档中
并且也会在每个需要它们的路径操作内的 API 文档中使用
编辑器支持¶
在你的编辑器中,函数内部,你将随处获得类型提示和补全(如果你接收的是 dict
而不是 Pydantic 模型,则不会发生这种情况)
你还会收到针对不正确类型操作的错误检查
这并非偶然,整个框架都是围绕这个设计构建的。
并且在任何实现之前,它在设计阶段就经过了彻底的测试,以确保它能与所有编辑器一起工作。
甚至 Pydantic 本身也进行了一些更改以支持这一点。
之前的截图是在 Visual Studio Code 中截取的。
但你会在 PyCharm 和大多数其他 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):
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
🤓 其他版本和变体
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
请求体 + 路径参数¶
你可以同时声明路径参数和请求体。
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()}
🤓 其他版本和变体
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
🤓 其他版本和变体
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
函数参数将被识别为如下:
- 如果参数也在路径中声明,它将被用作路径参数。
- 如果参数是单一类型(如
int
、float
、str
、bool
等),它将被解释为查询参数。 - 如果参数声明为 Pydantic 模型的类型,它将被解释为请求体。
注意
FastAPI 会知道 q
的值不是必需的,因为有默认值 = None
。
str | None
(Python 3.10+) 或 Union[str, None]
(Python 3.8+) 中的 Union
并非 FastAPI 用来判断值是否非必需的,它会根据 = None
的默认值来判断其为非必需。
但添加类型注解将使你的编辑器提供更好的支持并检测错误。
不使用 Pydantic¶
如果你不想使用 Pydantic 模型,你也可以使用 Body 参数。请参阅 请求体 - 多个参数:请求体中的单一值 的文档。