【学习记录】FastAPI 参数详解:路径参数、查询参数与请求体 ------ 从入门到实战
FastAPI 是一款现代、高性能的 Python Web 框架,凭借自动类型转换、数据验证和 OpenAPI 文档生成等特性,迅速成为 API 开发的首选。本文系统讲解 FastAPI 中三种最核心的参数传递方式------路径参数 、查询参数 和 请求体,从基础用法到进阶验证,从混合使用到嵌套模型,辅以完整的代码示例和测试命令,帮助你全面掌握 FastAPI 的参数处理机制。
📌 目录
- [路径参数(Path Parameters)](#路径参数(Path Parameters))
- 1.1 基础用法:类型注解自动转换
- 1.2 进阶:使用
Path添加验证与元数据
- [查询参数(Query Parameters)](#查询参数(Query Parameters))
- 2.1 基础用法:类型注解 + 默认值
- 2.2 必填查询参数
- 2.3 使用
Query添加验证和描述 - 2.4 列表参数(多值)
- 2.5 布尔类型参数
- [请求体(Request Body)](#请求体(Request Body))
- 3.1 使用 Pydantic
BaseModel定义数据结构 - 3.2 使用
Field添加验证和描述 - 3.3 在路径操作函数中使用请求体
- 3.4 混合使用:路径参数 + 查询参数 + 请求体
- 3.5 嵌套模型与复杂结构
- 3.1 使用 Pydantic
- 完整实战示例
- 总结
一、路径参数(Path Parameters)
路径参数是 URL 路径的一部分,用于唯一标识资源 ,例如 /items/42 中的 42。FastAPI 通过类型注解自动解析、转换和验证路径参数,并提供 Path 类来添加额外的元数据、验证规则和文档描述。
1.1 基础用法:类型注解自动转换
只需在函数参数中声明与路径变量同名的参数,并标注类型,FastAPI 会自动:
- 从路径中提取对应值
- 转换为声明的类型(如
int、float、str) - 若转换失败或不符合类型,自动返回清晰的错误信息
python
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def get_item(item_id: int): # 类型注解 int
return {"item_id": item_id, "message": f"商品 {item_id}"}
测试:
bash
# 正常访问
curl http://127.0.0.1:8000/items/42
# 输出: {"item_id":42,"message":"商品 42"}
# 类型错误
curl http://127.0.0.1:8000/items/abc
# 输出: 422 错误,提示 item_id 应为整数
1.2 进阶:使用 Path 添加验证与元数据
Path 是 FastAPI 提供的函数,用于为路径参数附加额外信息,例如:
- 标题 (
title):文档中显示的名称 - 描述 (
description):参数说明 - 验证规则 :
gt(大于)、ge(大于等于)、lt(小于)、le(小于等于)、regex(正则表达式)等 - 示例值 (
example):生成文档时的示例 - 废弃标记 (
deprecated)
python
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def get_item(
item_id: int = Path(
title="商品ID",
description="必须是大于 0 的整数,用于唯一标识商品",
gt=0,
example=123
)
):
return {"item_id": item_id}
测试:
bash
# 传入 0 或负数,触发验证错误
curl http://127.0.0.1:8000/items/0
# 输出: 422 错误,{"detail":[{"type":"greater_than","msg":"Input should be greater than 0",...}]}
在生成的 OpenAPI 文档(/docs)中,会显示参数名称、类型、描述和示例值。
二、查询参数(Query Parameters)
查询参数是 URL 中 ? 后面以 key=value 形式传递的参数,常用于过滤、排序、分页 等可选操作。FastAPI 通过函数参数的类型注解自动识别查询参数,并支持使用 Query 类添加验证和元数据。
2.1 基础用法:类型注解 + 默认值
直接在路径操作函数中定义非路径参数,并给予默认值(可选)或没有默认值(必填)。FastAPI 会自动从查询字符串中提取同名参数。
python
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/")
async def list_items(limit: int = 10, skip: int = 0):
return {"limit": limit, "skip": skip}
测试:
bash
# 使用自定义值
curl "http://127.0.0.1:8000/items/?limit=5&skip=10"
# 输出: {"limit":5,"skip":10}
# 不传参数,使用默认值
curl "http://127.0.0.1:8000/items/"
# 输出: {"limit":10,"skip":0}
2.2 必填查询参数
去掉默认值,则该查询参数为必填项。
python
@app.get("/users/")
async def get_users(name: str): # 没有默认值,必填
return {"name": name}
测试:
bash
# 缺少必填参数
curl "http://127.0.0.1:8000/users/"
# 输出: 422 错误
# 正确
curl "http://127.0.0.1:8000/users/?name=alice"
2.3 使用 Query 类添加验证和描述
Query 用于为查询参数附加额外信息:标题、描述、默认值、验证规则(min_length、max_length、regex、gt、ge、lt、le)、废弃标记等。
python
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def list_items(
limit: int = Query(10, ge=1, le=100, description="每页数量"),
skip: int = Query(0, ge=0, title="偏移量"),
q: str = Query(None, max_length=50, regex="^[a-zA-Z0-9]+$")
):
return {"limit": limit, "skip": skip, "q": q}
测试:
bash
# 超出范围
curl "http://127.0.0.1:8000/items/?limit=200"
# 422 错误
# 正则不匹配
curl "http://127.0.0.1:8000/items/?q=hello!"
# 422 错误
2.4 查询参数中的列表(多值)
使用 List 类型或 Query 的 default 参数接收多个相同名称的参数。
python
from typing import List
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def list_items(tags: List[str] = Query(["all"])):
return {"tags": tags}
测试:
bash
curl "http://127.0.0.1:8000/items/?tags=python&tags=fastapi"
# 输出: {"tags":["python","fastapi"]}
curl "http://127.0.0.1:8000/items/"
# 输出: {"tags":["all"]}
2.5 布尔类型查询参数
布尔值支持多种真值表示:true、True、1、on、yes 视为 True;false、False、0、off、no 视为 False。
python
@app.get("/users/")
async def get_users(active: bool = True):
return {"active": active}
测试:
bash
curl "http://127.0.0.1:8000/users/?active=false"
# 输出: {"active":false}
三、请求体(Request Body)
请求体用于传输客户端向服务器发送的复杂数据,例如创建资源时的 JSON 对象。FastAPI 通过 Pydantic 模型 来声明请求体的数据结构,并自动完成解析、验证和文档生成。
3.1 使用 Pydantic BaseModel 定义数据模型
BaseModel 是 Pydantic 提供的基础类,用于定义数据结构和验证规则。
python
from pydantic import BaseModel
class Item(BaseModel):
name: str
price: float
is_available: bool = True # 带默认值,可选字段
- 每个属性通过类型注解声明字段类型。
- 有默认值的字段为可选(请求时可不提供),无默认值的字段为必填。
- 当客户端发送的 JSON 不符合类型要求时,FastAPI 会自动返回 422 错误。
3.2 使用 Field 添加验证和描述
Field 是 Pydantic 提供的函数,可为字段附加额外的元数据和验证规则:默认值、标题、描述、gt、ge、lt、le、min_length、max_length、regex、示例值等。
python
from pydantic import BaseModel, Field
class Item(BaseModel):
name: str = Field(..., title="商品名称", max_length=50, example="智能手机")
price: float = Field(..., gt=0, le=10000, description="价格,必须为正数且不超过10000")
is_available: bool = Field(default=True, title="是否上架")
tags: list[str] = Field(default=[], max_items=5)
...表示该字段是必填的(...是 Python 的Ellipsis对象,Pydantic 约定用于表示没有默认值)。- 如果不提供默认值且不使用
...,字段也是必填的,但推荐使用...以明确表达意图。
3.3 在路径操作函数中使用请求体
只需将模型类型作为参数声明,FastAPI 就会自动从请求体中读取 JSON 并转换为该模型实例。
python
from fastapi import FastAPI
from pydantic import BaseModel, Field
app = FastAPI()
class Item(BaseModel):
name: str = Field(..., min_length=1, max_length=50)
price: float = Field(..., gt=0)
is_available: bool = True
@app.post("/items/")
async def create_item(item: Item):
return {"message": f"商品 {item.name} 创建成功", "item": item.dict()}
测试:
bash
curl -X POST "http://127.0.0.1:8000/items/" \
-H "Content-Type: application/json" \
-d '{"name":"平板电脑","price":3999.99,"stock":10}'
# 输出: {"message":"商品 平板电脑 创建成功","item":{"name":"平板电脑","price":3999.99,"is_available":true}}
3.4 混合使用:路径参数 + 查询参数 + 请求体
FastAPI 能自动区分不同类型的参数:路径参数、查询参数和请求体,无需额外标记。
python
from fastapi import FastAPI, Path, Query
from pydantic import BaseModel, Field
app = FastAPI()
class Item(BaseModel):
name: str
price: float = Field(..., gt=0)
@app.put("/items/{item_id}")
async def update_item(
item_id: int = Path(..., gt=0), # 路径参数
q: str = Query(None, max_length=10), # 查询参数
item: Item = None # 请求体
):
return {"item_id": item_id, "query": q, "item": item}
测试:
bash
curl -X PUT "http://127.0.0.1:8000/items/42?q=urgent" \
-H "Content-Type: application/json" \
-d '{"name":"游戏机","price":2999.99}'
# 输出: {"item_id":42,"query":"urgent","item":{"name":"游戏机","price":2999.99}}
3.5 嵌套模型与复杂结构
Pydantic 支持嵌套模型、列表、字典等复杂类型。
python
from pydantic import BaseModel, Field
from typing import List
class SubItem(BaseModel):
sub_name: str
count: int = Field(..., ge=1)
class MainItem(BaseModel):
id: int
details: SubItem
tags: List[str] = []
请求体示例:
json
{
"id": 100,
"details": {"sub_name": "配件", "count": 3},
"tags": ["电子", "促销"]
}
四、完整实战示例
以下是一个整合了路径参数、查询参数、请求体,并包含完整验证和错误处理的示例:
python
from fastapi import FastAPI, status, Path, Query
from pydantic import BaseModel, Field
from typing import Optional, List
app = FastAPI(title="商品管理API", description="演示路径参数、查询参数和请求体")
# ---------- 数据模型 ----------
class ItemCreate(BaseModel):
name: str = Field(..., min_length=1, max_length=100, example="笔记本电脑")
price: float = Field(..., gt=0, le=99999, example=5999.99)
stock: int = Field(0, ge=0, description="库存数量")
tags: List[str] = Field(default=[], max_items=10)
class ItemUpdate(BaseModel):
name: Optional[str] = Field(None, min_length=1, max_length=100)
price: Optional[float] = Field(None, gt=0, le=99999)
stock: Optional[int] = Field(None, ge=0)
# ---------- 端点 ----------
@app.post("/items/", status_code=status.HTTP_201_CREATED)
async def create_item(item: ItemCreate):
# 模拟数据库保存
return {"message": "商品创建成功", "item": item.dict()}
@app.get("/items/{item_id}")
async def get_item(
item_id: int = Path(..., gt=0, title="商品ID"),
include_stock: bool = Query(False, description="是否返回库存信息")
):
# 模拟从数据库查询
item_data = {"id": item_id, "name": "示例商品", "price": 99.99, "stock": 10}
if not include_stock:
item_data.pop("stock")
return item_data
@app.put("/items/{item_id}")
async def update_item(
item_id: int = Path(..., gt=0),
update_data: ItemUpdate = None,
q: str = Query(None, max_length=20)
):
# 模拟更新
return {
"item_id": item_id,
"query": q,
"updated_fields": update_data.dict(exclude_unset=True) if update_data else {}
}
@app.delete("/items/{item_id}")
async def delete_item(
item_id: int = Path(..., gt=0),
permanent: bool = Query(False, description="是否永久删除")
):
return {"item_id": item_id, "permanent": permanent, "message": "删除成功"}
# ---------- 高级查询:列表参数 ----------
@app.get("/search/")
async def search_items(
q: str = Query(..., min_length=1, description="搜索关键词"),
category: List[str] = Query([], description="分类过滤,可多个")
):
return {"query": q, "categories": category}
测试命令示例:
bash
# 创建商品
curl -X POST "http://127.0.0.1:8000/items/" -H "Content-Type: application/json" -d '{"name":"手机","price":2999.99,"stock":50,"tags":["电子","促销"]}'
# 查询商品(不返回库存)
curl "http://127.0.0.1:8000/items/1"
# 查询商品(返回库存)
curl "http://127.0.0.1:8000/items/1?include_stock=true"
# 搜索(多分类)
curl "http://127.0.0.1:8000/search/?q=手机&category=电子&category=数码"
五、总结
| 参数类型 | 位置 | 典型用途 | 声明方式 | 验证工具 |
|---|---|---|---|---|
| 路径参数 | URL 路径中 /{param} |
资源标识(如 ID) | 函数参数 + 类型注解 | Path |
| 查询参数 | URL ?key=value |
过滤、排序、分页 | 函数参数 + 默认值 | Query |
| 请求体 | HTTP 请求体(JSON) | 创建/更新资源 | Pydantic 模型 | BaseModel + Field |
核心优势:
- ✅ 自动类型转换与验证,减少手动检查代码。
- ✅ 自动生成 OpenAPI 文档(
/docs),前后端联调高效。 - ✅ 支持复杂嵌套结构,易于扩展。
- ✅ 路径参数、查询参数、请求体可自由混合使用,框架自动区分。
掌握这三类参数,你就能轻松构建出健壮、规范、易维护的 FastAPI 应用程序。下一步可以学习 依赖注入 、中间件 和 后台任务,让你的 API 更加专业。