FastAPI 请求体参数详解
1. 参数类型
FastAPI 中的参数主要分为以下三种类型:
- 路径参数(Path Parameters):如果参数出现在路径中,FastAPI 默认将其视为路径参数。
- 查询参数(Query Parameters):如果单个参数未在路径中出现,默认会被视为查询参数,即使使用 POST 方法也是如此。
- 请求体参数(Body Parameters):如果参数类型是一个 Pydantic 模型,则该参数会被默认视为请求体参数。
2. 单个请求体参数
要将单个参数作为请求体参数,需要使用 Body
显式声明。
from fastapi import Body, FastAPI
from typing import Annotated
app = FastAPI()
@app.post("/items/")
async def read_item(item_id: Annotated[int, Body()]):
return {"item_id": item_id}
测试方法:
- FastAPI 提供的 Docs 界面:在浏览器中访问
/docs
,通过界面测试接口。 - Requests 库:
import requests
url = 'http://127.0.0.1:8009/items/'
res = requests.put(url, json=5)
print(res.text) # 输出:{"item_id":5}
3. 多个请求体参数
当有多个请求体参数时,可以将它们嵌套在一个字典中传递。
from fastapi import Body, FastAPI
from typing import Annotated
app = FastAPI()
@app.post("/items/")
async def read_item(item_id: Annotated[int, Body()], name: Annotated[str, Body()]):
return {"item_id": item_id, "name": name}
测试方法:
- Requests 库:
url = 'http://127.0.0.1:8009/items/'
data = {"item_id": 5, "name": "张三"}
res = requests.put(url, json=data)
print(res.text) # 输出:{"item_id":5,"name":"张三"}
4. Pydantic 模型请求体参数
可以直接将 Pydantic 模型作为请求体参数。
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
@app.post("/items/")
async def read_item(item: Item):
return {"name": item.name, "price": item.price}
测试方法:
- Requests 库:
url = 'http://127.0.0.1:8009/items/'
data = {"name": "细胞生物学", "description": "考研书籍", "price": 35.8, "tax": 0.6}
res = requests.post(url, json=data)
print(res.text) # 输出:{"name":"细胞生物学","price":35.8}
5. 混合使用 Path、Query 和请求体参数
可以同时使用路径参数、查询参数和请求体参数。
from fastapi import Body, FastAPI
from typing import Annotated
app = FastAPI()
@app.post("/items/{name}")
async def read_item(name: str, age: int, item_id: Annotated[int, Body()]):
return {"name": name, "age": age, "item_id": item_id}
测试方法:
- Requests 库:
url = 'http://127.0.0.1:8009/items/张三?age=18'
res = requests.post(url, json=5)
print(res.text) # 输出:{"name":"张三","age":18,"item_id":5}
6. 多个 Pydantic 模型请求体参数
当函数中有多个 Pydantic 模型参数时,FastAPI 会自动将参数名称作为请求体中的键。
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
class User(BaseModel):
username: str
full_name: str | None = None
@app.post("/items/")
async def read_item(item: Item, user: User):
return {"name": item.name, "price": item.price, "user": user}
测试方法:
- Requests 库:
url = 'http://127.0.0.1:8009/items/'
data = {
"item": {"name": "细胞生物学", "description": "考研书籍", "price": 35.8, "tax": 0.6},
"user": {"username": "张三", "full_name": "张三丰"}
}
res = requests.post(url, json=data)
print(res.text) # 输出:{"name":"细胞生物学","price":35.8,"user":{"username":"张三","full_name":"张三丰"}}
7. 嵌入单个请求体参数
如果希望将单个 Pydantic 模型参数嵌入到 JSON 的键中,可以使用 Body(embed=True)
。
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
@app.post("/items/")
async def read_item(item: Item = Body(embed=True)):
return {"name": item.name, "price": item.price}
测试方法:
- Requests 库:
url = 'http://127.0.0.1:8009/items/'
data = {
"item": {"name": "细胞生物学", "description": "考研书籍", "price": 35.8, "tax": 0.6}
}
res = requests.post(url, json=data)
print(res.text) # 输出:{"name":"细胞生物学","price":35.8}
8. 总结
- 路径参数:直接出现在 URL 路径中。
- 查询参数:通过 URL 的查询字符串传递。
- 请求体参数:通过 JSON 格式的请求体传递。
- Pydantic 模型:可以简化复杂的请求体结构,并提供自动校验功能。
- 混合使用:可以同时使用路径参数、查询参数和请求体参数。
通过以上内容,可以灵活地处理各种类型的参数,满足不同的 API 需求。
FastAPI 额外参数信息详解
1. 核心概念理解
- 校验与元数据声明:通过
Field
在数据模型中定义字段约束条件(如数值范围、字符串长度)和描述信息 - 文档集成机制:所有声明信息会自动转换为OpenAPI规范,驱动交互式文档生成
- 作用域区分:
Query/Path/Body
:处理请求参数的位置约束Field
:专注数据模型内部的字段验证
2. Field 参数深度解析
基础结构示例:
from pydantic import BaseModel, Field
class Product(BaseModel):
sku: str = Field(
min_length=8,
max_length=12,
pattern="^[A-Z]{3}-\\d+$",
examples=["ABC-123456"]
)
stock: int = Field(
default=0,
ge=0,
description="当前库存数量",
json_schema_extra={"unit": "件"}
)
常用参数对照表:
参数 | 适用类型 | 作用 | 示例值 |
---|---|---|---|
gt/ge | 数值类型 | 数值下限约束 | gt=0 |
lt/le | 数值类型 | 数值上限约束 | lt=100 |
min_length | 字符串/集合 | 最小长度限制 | min_length=5 |
max_length | 字符串/集合 | 最大长度限制 | max_length=20 |
pattern | 字符串 | 正则表达式验证 | pattern="^\\d+$" |
default | 任意类型 | 字段默认值 | default="new" |
title | 任意类型 | OpenAPI文档中的字段标题 | title="产品编号" |
description | 任意类型 | 字段详细说明 | description="..." |
3. 高级配置技巧
自定义文档示例:
class ExperimentalData(BaseModel):
timestamp: float
value: float = Field(..., gt=0)
model_config = {
"json_schema_extra": {
"examples": [{
"timestamp": 1717392600.0,
"value": 3.1415
}, {
"timestamp": 1717392601.5,
"value": 2.7182
}]
}
}
多层级嵌套验证:
class Address(BaseModel):
city: str = Field(max_length=20)
street: str = Field(description="街道信息")
class UserProfile(BaseModel):
name: str = Field(min_length=2, max_length=20)
age: int = Field(ge=18, le=100)
address: Address = Field(..., description="居住地址")
4. 开发注意事项
-
版本兼容性:
- Python 3.8+ 需要使用
Optional
类型声明
from typing import Optional description: Optional[str] = Field(default=None)
- Python 3.8+ 需要使用
-
性能优化:
- 复杂正则表达式可能影响验证性能
- 数值范围检查优先于正则表达式验证
-
文档增强:
- 使用
deprecated
参数标记即将废弃的字段
old_field: str = Field(deprecated=True)
- 使用
5. 调试与验证
请求模拟工具:
# 使用HTTPX进行测试
import httpx
async def test_model():
async with httpx.AsyncClient(app=app, base_url="http://test") as client:
response = await client.post("/items/7", json={
"item": {
"name": "Test",
"price": 19.99
}
})
assert response.status_code == 200
常见错误处理:
422 Unprocessable Entity
:表示数据验证失败- 错误响应包含详细验证失败信息:
{ "detail": [ { "loc": ["body", "item", "price"], "msg": "ensure this value is greater than 0", "type": "value_error.number.not_gt" } ] }
6. 可视化文档效果
配置完成后,访问/docs
路由可查看自动生成的交互文档:
- 模型字段显示所有约束条件
- 示例数据预填充在请求体编辑器中
- 参数描述信息显示为帮助文本
FastAPI 高级功能解析
一、Field 附加参数
在 Pydantic 模型中通过 Field
添加示例数据:
from pydantic import BaseModel, Field
class Item(BaseModel):
name: str = Field(examples=["Foo"])
description: str | None = Field(default=None, examples=["示例描述"])
price: float = Field(examples=[35.4])
tax: float | None = Field(default=None, examples=[3.2])
- 文档效果:在 Swagger UI 的 Schema 部分显示预设示例
- 数据校验:仅验证字段类型和约束条件,不检查示例内容
二、Body 额外参数
在请求体参数中使用 example
或 examples
:
from fastapi import Body
body_example = {
"name": "分子生物学",
"price": 42.0,
"tax": 2.8
}
@app.post("/items/{item_id}")
async def update_item(
item_id: UUID,
item: Item = Body(embed=True, example=body_example)
):
return {"item_id": item_id, "item": item}
embed=True
表示将请求体包装在item
字段内- 文档显示:Swagger UI 请求体示例显示完整 JSON 结构
三、复杂数据类型处理
FastAPI 支持自动转换的常见类型:
类型 | 输入格式 | Python 转换 |
---|---|---|
UUID | 标准 UUID 字符串 | uuid.UUID |
datetime | ISO 8601 (e.g., 2024-01-24T07:42:54) | datetime.datetime |
time | HH:MM:SS[.ffffff] | datetime.time |
timedelta | 浮点数(总秒数) | datetime.timedelta |
示例端点:
@app.post("/events/{event_id}")
async def create_event(
event_id: UUID,
start: datetime,
duration: timedelta = Body(...)
):
end = start + duration
return {"event_id": event_id, "end_time": end}
四、数据校验机制
自动校验场景示例:
# 模型定义
class Meeting(BaseModel):
time: datetime
participants: conint(ge=1, le=10) # 1-10人
- 合法请求:
{"time": "2024-03-15T14:30:00", "participants": 5}
- 非法请求:
将返回 422 错误,错误详情包含:{"time": "2024-02-30T25:61:00", "participants": 0}
{ "loc": ["body", "time"], "msg": "invalid datetime format", "type": "value_error.datetime" }
五、实践建议
-
文档优化技巧:
- 为枚举类型添加描述:
Field(description="物品分类")
- 使用
examples
展示多种情况:price: float = Field(examples=[29.9, 99.0, 159.0])
- 为枚举类型添加描述:
-
调试方法:
# 查看原始请求数据 print(await request.json()) # 验证数据转换结果 print(start_datetime.isoformat())
-
安全注意事项:
- 时间字段建议明确时区处理
- UUID 路径参数自动拦截非法格式请求
六、测试验证流程
from pydantic import validator
class Payment(BaseModel):
card_number: str = Field(regex=r"^\d{16}$")
expiry_date: str = Field(regex=r"^(0[1-9]|1[0-2])\/?([0-9]{4}|[0-9]{2})$")
@validator("expiry_date")
def validate_expiry(cls, v):
month, year = v.split('/')
if int(year) < datetime.now().year % 100:
raise ValueError("卡片已过期")
return v
这些功能组合使用可以创建出:
验证失败时返回的响应示例:
{
"detail": [
{
"loc": ["body", "age"],
"msg": "ensure this value is less than or equal to 150",
"type": "value_error.number.not_le",
"ctx": {"limit_value": 150}
}
]
}
5. 高级校验示例
结合验证器和正则表达式:
-
生成测试 UUID:
import uuid test_id = uuid.uuid4()
-
发送复合类型请求:
import requests data = { "start": "2024-03-15T09:00:00", "duration": 3600.0 # 1小时 } response = requests.post(f"http://api/events/{test_id}", json=data) print(response.json())
预期响应包含计算后的结束时间:
{ "event_id": "550e8400-e29b-41d4-a716-446655440000", "end_time": "2024-03-15T10:00:00" }
-
触发校验错误:
invalid_data = {"participants": 11} response = requests.post("/meetings", json=invalid_data) assert response.status_code == 422
以下是对FastAPI数据校验与元数据配置的详细说明:
1. Field参数扩展校验
在Pydantic模型中使用
Field
添加校验规则:from pydantic import BaseModel, Field class User(BaseModel): username: str = Field( min_length=3, max_length=20, regex="^[a-zA-Z0-9_]+$", example="john_doe", description="用户名需包含字母数字和下划线" ) age: int = Field( gt=0, le=150, example=25, title="用户年龄" ) tags: list[str] = Field( default_factory=list, max_items=5, example=["python", "web"] )
2. 示例数据配置
两种方式添加示例数据:
模型内部配置:
class Item(BaseModel): name: str price: float class Config: schema_extra = { "example": { "name": "Wireless Mouse", "price": 29.99 } }
请求体参数配置:
@app.post("/items/") async def create_item(item: Item = Body( examples={ "normal": { "summary": "标准示例", "value": {"name": "键盘", "price": 199.0} }, "discount": { "summary": "促销示例", "value": {"name": "显示器", "price": 899.0} } } )): return item
3. 支持的数据类型
FastAPI自动处理的数据类型示例:
类型 示例值 说明 datetime.datetime
"2023-07-20T14:30:00"
ISO 8601格式日期时间 uuid.UUID
"f81d4fae-7dec-11d0-a765-00a0c91e6bf6"
标准UUID格式 EmailStr
"user@example.com"
邮箱格式验证 IPvAnyAddress
"192.168.1.1"
IP地址验证 PaymentCardNumber
"4242424242424242"
信用卡号格式验证 4. 校验机制原理
当请求到达时,FastAPI会执行以下验证流程:
- 类型检查:验证输入是否符合字段声明的类型
- 约束验证:检查
Field
参数定义的条件(如gt=0
) - 自定义验证:通过
@validator
装饰器添加的自定义规则 - 错误聚合:收集所有验证错误并统一返回
- 自文档化的API接口
- 强类型约束的数据模型
- 自动化的输入验证机制
- 清晰的错误反馈信息
- 可维护的代码结构
from pydantic import validator
class Payment(BaseModel):
card_number: str = Field(regex=r"^\d{16}$")
expiry_date: str = Field(regex=r"^(0[1-9]|1[0-2])\/?([0-9]{4}|[0-9]{2})$")
@validator("expiry_date")
def validate_expiry(cls, v):
month, year = v.split('/')
if int(year) < datetime.now().year % 100:
raise ValueError("卡片已过期")
return v
对FastAPI数据校验与元数据配置的详细说明:
1. Field参数扩展校验
在Pydantic模型中使用Field
添加校验规则:
from pydantic import BaseModel, Field
class User(BaseModel):
username: str = Field(
min_length=3,
max_length=20,
regex="^[a-zA-Z0-9_]+$",
example="john_doe",
description="用户名需包含字母数字和下划线"
)
age: int = Field(
gt=0,
le=150,
example=25,
title="用户年龄"
)
tags: list[str] = Field(
default_factory=list,
max_items=5,
example=["python", "web"]
)
2. 示例数据配置
两种方式添加示例数据:
模型内部配置:
class Item(BaseModel):
name: str
price: float
class Config:
schema_extra = {
"example": {
"name": "Wireless Mouse",
"price": 29.99
}
}
请求体参数配置:
@app.post("/items/")
async def create_item(item: Item = Body(
examples={
"normal": {
"summary": "标准示例",
"value": {"name": "键盘", "price": 199.0}
},
"discount": {
"summary": "促销示例",
"value": {"name": "显示器", "price": 899.0}
}
}
)):
return item
3. 支持的数据类型
FastAPI自动处理的数据类型示例:
类型 | 示例值 | 说明 |
---|---|---|
datetime.datetime | "2023-07-20T14:30:00" | ISO 8601格式日期时间 |
uuid.UUID | "f81d4fae-7dec-11d0-a765-00a0c91e6bf6" | 标准UUID格式 |
EmailStr | "user@example.com" | 邮箱格式验证 |
IPvAnyAddress | "192.168.1.1" | IP地址验证 |
PaymentCardNumber | "4242424242424242" | 信用卡号格式验证 |
4. 校验机制原理
当请求到达时,FastAPI会执行以下验证流程:
- 类型检查:验证输入是否符合字段声明的类型
- 约束验证:检查
Field
参数定义的条件(如gt=0
) - 自定义验证:通过
@validator
装饰器添加的自定义规则 - 错误聚合:收集所有验证错误并统一返回
验证失败时返回的响应示例:
{
"detail": [
{
"loc": ["body", "age"],
"msg": "ensure this value is less than or equal to 150",
"type": "value_error.number.not_le",
"ctx": {"limit_value": 150}
}
]
}
5. 高级校验示例
结合验证器和正则表达式:
from pydantic import validator
class Payment(BaseModel):
card_number: str = Field(regex=r"^\d{16}$")
expiry_date: str = Field(regex=r"^(0[1-9]|1[0-2])\/?([0-9]{4}|[0-9]{2})$")
@validator("expiry_date")
def validate_expiry(cls, v):
month, year = v.split('/')
if int(year) < datetime.now().year % 100:
raise ValueError("卡片已过期")
return v
这些功能组合使用可以创建出:
- 自文档化的API接口
- 强类型约束的数据模型
- 自动化的输入验证机制
- 清晰的错误反馈信息
- 可维护的代码结构
嵌套模型的概念
在 FastAPI 中,嵌套模型是指一个 Pydantic 模型的属性可以是另一个 Pydantic 模型。这种设计允许处理复杂的 JSON 数据结构,并且能够自动进行数据校验、转换和文档生成。
示例代码
以下是一个简单的示例,展示了如何在 FastAPI 中使用嵌套模型:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Image(BaseModel):
url: str
name: str
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
image: Image | None = None
@app.post("/items/{item_id}")
async def update_item(item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
测试方法
可以使用 requests
库发送 POST 请求来测试这个 API:
import requests
url = 'http://127.0.0.1:8000/items/5'
data = {
"name": "Foo",
"description": "The pretender",
"price": 42.0,
"tax": 3.2,
"image": {
"url": "http://example.com/baz.jpg",
"name": "The Foo live"
}
}
res = requests.post(url, json=data)
print(res.text) # 输出:JSON 格式的响应数据
深度嵌套
FastAPI 支持多层嵌套的模型,这意味着可以在一个模型中嵌套另一个模型,而嵌套的模型又可以继续嵌套其他模型。这种设计非常适合处理复杂的 JSON 数据结构。
自动校验与文档生成
使用 Pydantic 模型定义嵌套结构后,FastAPI 会自动进行数据校验,确保传入的数据符合模型定义。同时,FastAPI 还会自动生成 API 文档,展示每个字段的类型和描述,方便开发者理解和使用 API。
总结
通过使用 FastAPI 的嵌套模型功能,可以轻松处理复杂的 JSON 数据结构,并获得自动校验、数据转换和文档生成的功能。这种设计使得 API 开发更加高效和可靠。
FastAPI Cookie 参数详解
定义 Cookie 参数
在 FastAPI 中,Cookie 参数可以通过 Cookie
工厂函数来声明。这种方式与 Query 参数和 Path 参数的声明方式类似,但需要明确指定参数来自 Cookie。
from typing import Annotated
from fastapi import Cookie, FastAPI
app = FastAPI()
@app.get("/items/")
async def read_items(ads_id: Annotated[str | None, Cookie()] = None):
return {"ads_id": ads_id}
在上述代码中,ads_id
是一个可选的 Cookie 参数,类型为 str
或 None
。Cookie()
工厂函数告诉 FastAPI 该参数来自 Cookie。
使用 requests
库测试
为了测试上述代码,可以使用 requests
库发送带有 Cookie 的 GET 请求。
import requests
url = 'http://127.0.0.1:8009/items/'
headers = {"Cookie": "ads_id=你好"}
res = requests.get(url, headers=headers)
print(res.text) # 输出:{"ads_id":"你好"}
如果未设置 ads_id
Cookie,则返回值为 {"ads_id": null}
。确保 headers
中的 Cookie
格式正确,例如 key=value
。
常见问题及解决方法
问题 1:无法识别 Cookie
- 原因:可能是因为
headers
格式不正确或服务端未正确解析 Cookie。 - 解决方法:
- 确保
headers
中的Cookie
格式为key=value
。 - 检查 FastAPI 服务端是否正常运行。
- 确保
问题 2:Cookie 值为空
- 原因:未传递正确的 Cookie 或未设置默认值。
- 解决方法:
- 确保请求中包含正确的 Cookie。
- 在路径操作函数中为 Cookie 参数设置默认值。
总结
- Cookie 参数:通过
Cookie
工厂函数声明,可以从 HTTP 请求中提取 Cookie 数据。 - 声明方式:与 Query 参数和 Path 参数类似,但需要明确使用
Cookie
。 - 测试方法:使用
requests
库发送带有Cookie
头的请求,验证功能是否正常。
通过以上内容,可以灵活地在 FastAPI 中处理 Cookie 数据,满足各种应用场景的需求。
FastAPI Header 参数详解
1. 概述
FastAPI 提供了 Header
工厂函数,用于从 HTTP 请求头中提取参数。与 Query、Path 和 Cookie 参数类似,Header 参数需要显式声明,以避免被误解为其他类型的参数。
2. 基本用法
通过 Header()
声明参数,FastAPI 会自动从请求头中提取对应的值。以下是一个简单的示例:
from fastapi import FastAPI, Header
app = FastAPI()
@app.get("/items/")
async def read_items(user_agent: str = Header(None)):
return {"User-Agent": user_agent}
user_agent
参数:通过Header()
声明,提取请求头中的User-Agent
。- 默认值:如果请求中未包含
User-Agent
,返回值为None
。
3. 自定义 Header 名称
默认情况下,FastAPI 会将参数名转换为小写并添加连字符(如 user_agent
对应 User-Agent
)。如果需要使用自定义的 Header 名称,可以通过 alias
参数指定:
@app.get("/items/")
async def read_items(custom_header: str = Header(None, alias="X-Custom-Header")):
return {"Custom-Header": custom_header}
4. 多值 Header
某些 Header 可能包含多个值(如 Accept-Language
),可以通过 List
类型来接收这些值:
from typing import List
@app.get("/items/")
async def read_items(accept_language: List[str] = Header(None)):
return {"Accept-Language": accept_language}
5. 测试方法
使用 requests
库发送带有自定义 Header 的 GET 请求,验证 FastAPI 的 Header 参数功能:
import requests
url = 'http://127.0.0.1:8009/items/'
headers = {"User-Agent": "test", "X-Custom-Header": "custom-value"}
res = requests.get(url, headers=headers)
print(res.text) # 输出:{"User-Agent":"test", "Custom-Header":"custom-value"}
6. 总结
- Header 参数声明:使用
Header()
明确指定参数来自请求头。 - 自定义 Header 名称:通过
alias
参数指定自定义的 Header 名称。 - 多值 Header:使用
List
类型接收包含多个值的 Header。 - 测试:通过
requests
库模拟请求,验证 Header 参数功能。
FastAPI:Web框架学习参考
http://www.datawhale.cn/learn/summary/164
http://github.com/datawhalechina/wow-fullstack/tree/main/tutorial/FastAPI