FastAPI:(3)参数
概述
文章内容概述
graph TD
%% 核心参数类型
A[FastAPI参数] --> B[路径参数]
A --> C[查询参数]
A --> D[Cookie参数]
A --> E[Header参数]
A --> F[响应参数]
%% 路径参数分支
B --> B1[路径匹配优先级]
B --> B2[路径参数校验]
B --> B3[路径参数预设值]
B --> B4[包含路径的参数]
B1 -->|优先级规则| B1a["静态路由 > 动态路由"]
B2 -->|校验类型| B2a["数值校验(ge/le)"]
B3 -->|实现方式| B3a["Enum枚举"]
B4 -->|特殊语法| B4a["{file_path:path}"]
%% 查询参数分支
C --> C1[查询参数校验]
C --> C2[查询参数模型]
C1 -->|校验方法| C1a["长度/正则/必填"]
C2 -->|模型特性| C2a["Pydantic BaseModel"]
C2 -->|高级控制| C2b["禁止额外参数"]
%% Cookie/Header分支
D --> D1[Cookie参数模型]
E --> E1[Header参数模型]
D1 & E1 -->|共享特性| DE1["结构化验证"]
%% 响应控制分支
F --> F1[响应模型]
F --> F2[响应状态码]
F1 -->|核心功能| F1a["数据过滤"]
F1 -->|高级用法| F1b["response_model_include/exclude"]
F2 -->|常用状态码| F2a["200/201/404"]
%% 工具类概念
G[解包dict] -->|应用场景| G1["动态构建模型"]
H[模型继承] -->|优势| H1["减少代码重复"]
G & H -->|共用技术| GH1["Pydantic"]
1.路径参数
路径参数
路径参数是 FastAPI 中用于在 URL 路径中定义变量的一种机制。它允许你在 API 路径中嵌入变量值,使得客户端可以通过改变路径来访问不同的资源。路径参数通常与函数参数绑定,并支持类型声明与校验,是 RESTful 风格接口设计的重要组成部分。
重要特征:
- 动态路径识别:路径中通过
{}包含的变量实现动态路由匹配。 - 类型绑定与校验:支持 Python 类型注解,FastAPI 自动进行类型转换和校验。
- 自动文档生成:配合类型声明,能生成 OpenAPI 规范的接口文档。
- 请求参数与函数参数一致:路径中的参数会自动传递到路径处理函数中。
- 顺序与名称必须精确匹配:URL 路径定义中的参数名称和顺序必须与函数参数一致。
获取商品信息(正例)
路劲参数
现象:
一个电商平台定义路径 /products/{product_id},当用户访问 /products/123,系统将提取 product_id = 123 并查找对应商品详情。此时 product_id 被声明为整数类型。
特征对比
- 动态路径识别 ✅:路径中使用
{product_id}。 - 类型绑定与校验 ✅:声明为
int,非整数会被拦截。 - 请求参数与函数参数一致 ✅:
product_id直接传入处理函数。 - 自动文档生成 ✅:支持前端通过 Swagger UI 查看接口定义。
from fastapi import FastAPI
app = FastAPI()
@app.get("/products/{product_id}")
async def get_product(product_id: int):
return {"product_id": product_id, "status": "product found"}
- 使用
{product_id}实现路径中的动态变量。 product_id被声明为int类型,FastAPI 会自动类型转换。- 请求
/products/10时返回{"product_id": 10, "status": "product found"}。
参数校验(正例)
路径参数
- 使用
Path(..., ge=1)对路径参数进行校验,要求user_id >= 1。 - 请求
/users/3时返回{"user_id": 3}。 - 请求
/users/0会返回 422 错误,因为不满足约束条件。
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/users/{user_id}")
async def read_user(user_id: int = Path(..., title="The ID of the user", ge=1)):
return {"user_id": user_id}
未声明参数(反例)
路劲参数
- 尽管
order_id被定义为函数参数,但路径/orders/info并未包含{order_id}。 - 请求
/orders/info?order_id=123会尝试将其当作查询参数处理,而不是路径参数。 - 此接口本质上没有路径参数,与定义目标不符。
from fastapi import FastAPI
app = FastAPI()
@app.get("/orders/info")
async def get_order(order_id: int):
return {"order_id": order_id}
应用
路劲参数
- 资源标识与查询:需要根据唯一标识获取资源,比如用户、文章、订单、项目等。
GET /users/123 GET /articles/456 GET /orders/ABC-2023 - 嵌套路由与上下文定位:获取嵌套结构下的某些信息,例如某个订单下的商品,或某篇文章下的评论。
GET /orders/987/items GET /articles/123/comments - 资源操作与编辑:希望执行操作,比如编辑某个资源、删除、激活等。
PUT /products/321 DELETE /users/1001 POST /reports/2023/submit
路径匹配优先级
在 FastAPI 中,路径操作的定义顺序决定了 URL 匹配的优先级。由于路径是从上到下顺序解析的,当存在多个路径具有相似前缀或相同结构(如静态路径与动态参数路径),顺序不同将直接影响路由匹配的结果。静态路径应优先于动态路径定义,否则动态路径会错误地捕获本应静态匹配的请求。
重要特征:
- 匹配顺序决定行为:FastAPI 依照代码中路径操作的顺序从上到下进行匹配。
- 静态路径优先原则:必须先定义静态路径(如
/users/me),再定义包含路径参数的动态路径(如/users/{user_id})。 - 路径参数贪婪匹配:动态路径参数会尝试匹配所有非显式声明的路径段,容易误匹配静态路径。
- 路由歧义会导致逻辑错误:路径定义不当可能导致逻辑错误或异常行为,如静态路径被误识别为参数值
静态路由优先(正例)
路径匹配优先级
🔹 请求 /users/me
返回:{"user_id": "the current user"} ✅
(静态路径优先匹配成功)
🔹 请求 /users/john
返回:{"user_id": "john"} ✅
(动态路径正确匹配)
from fastapi import FastAPI
app = FastAPI()
@app.get("/users/me")
async def read_user_me():
return {"user_id": "the current user"}
@app.get("/users/{user_id}")
async def read_user(user_id: str):
return {"user_id": user_id}
动态路由优先(反例)
路径匹配优先级
🔹 请求 /users/me
返回:{"user_id": "me"} ❌
(被上面的动态路径 /users/{user_id} 抢先匹配)
🔹 请求 /users/john
返回:{"user_id": "john"} ✅
(正常匹配)
from fastapi import FastAPI
app = FastAPI()
@app.get("/users/{user_id}")
async def read_user(user_id: str):
return {"user_id": user_id}
@app.get("/users/me")
async def read_user_me():
return {"user_id": "the current user"}
应用
路劲匹配优先级应用
- 「静态路径」与「动态参数」共存的 API:希望同时支持:
/users/me—— 获取当前用户信息(静态路径),/users/{user_id}—— 获取指定用户信息(动态路径)。 - 多级路由嵌套的模块化设计:设计一个复杂业务系统,例如:
/orders/new:创建新订单/orders/{order_id}:获取订单信息/orders/{order_id}/items:获取订单内商品
匹配优先级的安排:/orders/new应在/orders/{order_id}之前声明/orders/{order_id}/items应在/orders/{order_id}之后声明
路劲参数预设值
在 FastAPI 中,可以使用 Python 的 Enum 枚举类型为路径参数定义一组固定的可选值(预设值)。这使得 API 路径参数只能接受预定义的合法值,从而提升类型安全性、增强参数校验能力,并自动反映在 API 文档中。
当 Enum 同时继承自 str 和 Enum 时,FastAPI 能将这些枚举值正确识别为字符串类型,并在自动生成的 OpenAPI 文档中呈现出所有可选值的下拉选项。
重要特征:
- 限定路径参数值范围:只能传入枚举类中定义的固定值,非法值将被拒绝。
- 提升类型安全性:防止路径参数传入任意字符串或无效值。
- 自动文档渲染友好:继承
str类型后,枚举值会正确显示为字符串,并在 Swagger UI 中可见。 - 增强可读性和维护性:将逻辑可接受值显式列出,增强代码语义清晰性。
枚举例子(正例)
路劲参数预设值
from enum import Enum # 导入 `Enum` 并创建继承自 `str` 和 `Enum` 的子类。
from fastapi import FastAPI
class ModelName(str, Enum): # 创建包含固定值的类属性,这些固定值是可用的有效值
alexnet = "alexnet"
resnet = "resnet"
lenet = "lenet"
app = FastAPI()
@app.get("/models/{model_name}")
async def get_model(model_name: ModelName): #使用 Enum 类(`ModelName`)创建使用类型注解的路径参数
if model_name is ModelName.alexnet: # #枚举类 `ModelName` 中的_枚举元素_支持比较操作:使
return {"model_name": model_name, "message": "Deep Learning FTW!"}
if model_name.value == "lenet": #用 `model_name.value` 或 `your_enum_member.value` 获取实际的值(本例中为**字符串**)
return {"model_name": model_name, "message": "LeCNN all the images"} # 即使嵌套在 JSON 请求体里(例如, `dict`),也可以从_路径操作_返回_枚举元素_。
角色特定访问路劲(正例)
路劲参数预设值
🔹 请求 /dashboard/editor
返回:{"access_granted_to": "editor"} ✅
🟢 特征对比说明:
- 使用
Role限定只允许三种角色访问。 - 语义清晰:通过枚举定义角色逻辑更明确。
- 验证自动化:无须手动校验角色合法性。
from enum import Enum
from fastapi import FastAPI
app = FastAPI()
class Role(str, Enum):
admin = "admin"
editor = "editor"
viewer = "viewer"
@app.get("/dashboard/{role}")
async def dashboard_access(role: Role):
return {"access_granted_to": role}
限定路劲合法值
路劲参数预设值
🔹 请求 /items/pen
返回:{"item_type": "pen"} ✅
🔹 请求 /items/laptop
返回:HTTP 422 错误 ❌,因为不是合法枚举值。
🟢 特征对比说明:
- 限定值范围:只能是
"book","pen","notebook"。 - 自动文档渲染:Swagger UI 显示下拉选项。
- 类型安全:只有定义过的
Enum值才合法。
from enum import Enum
from fastapi import FastAPI
app = FastAPI()
class ItemType(str, Enum):
book = "book"
pen = "pen"
notebook = "notebook"
@app.get("/items/{item_type}")
async def get_item(item_type: ItemType):
return {"item_type": item_type}
应用
路劲参数预设值应用
- 角色控制与权限路由:系统中有多个用户角色(如 admin、editor、viewer),希望根据角色定义不同的访问路径,且拒绝非法角色访问。
- 资源类型分类(如日志、商品、任务等):有一个通用接口,例如
/resources/{type},这个接口应只允许访问几种固定的资源类型,如log、task、config。 - 语言或地区本地化:希望通过路径
/docs/{lang}提供多语言版本的文档,如en,zh,fr。 - 版本控制路径:构建 API 时希望通过路径
/api/{version}/users来处理不同版本的数据。
包含路径的路劲参数
在 FastAPI 中,包含路径的路径参数是指路径参数中允许包含斜杠 /,即传入的参数值本身可以是一段完整的文件路径,例如 home/user/file.txt。这种用法突破了普通路径参数只能匹配单一路径段(即不含 /)的限制。
由于 OpenAPI 标准本身并不支持这样的路径参数声明(因为它难以静态分析和测试),FastAPI 借助底层框架 Starlette 提供的路径转换器(Path Converter) 来实现该功能,通过语法 /files/{file_path:path} 指定参数类型为 path,从而接收多个路径段。
重要特征:
- 支持多层路径嵌套:传入的路劲参数要以(/)开头,包含路劲的参数。非路劲参数与路由之间是双斜杠(//)
- 不被 OpenAPI 标准原生支持:FastAPI 可用,但不会自动为文档添加路径结构说明。
- 依赖 Starlette 提供的路径转换语法:例如
{param:path}。 - 不会影响文档运行:尽管文档缺失部分语义,但 API 可照常调用。
- 适用于文件系统场景:尤其用于文件路由、静态资源访问、配置路径解析等需求
文件访问(正例)
- 注意,包含
/home/johndoe/myfile.txt的路径参数要以斜杠(/)开头。 - 本例中的 URL 是
/files//home/johndoe/myfile.txt。注意,files和home之间要使用双斜杠(//)。
from fastapi import FastAPI
app = FastAPI()
@app.get("/files/{file_path:path}")
async def read_file(file_path: str):
return {"file_path": file_path}
普通路劲参数
🔹 请求 /files/home/user/data.txt
❌ 会导致 404 错误,因为:
{file_path}只匹配单个路径段(默认不能包含/),例如data.txt是合法的,而home/user/data.txt会被解释为多个路径段,无法匹配。
from fastapi import FastAPI
app = FastAPI()
@app.get("/files/{file_path}")
async def read_file(file_path: str):
return {"path": file_path}
应用
包含路劲的路劲参数应用
- ✅ 使用
/files/{file_path:path}适合:文件浏览器、远程路径资源管理、静态文件读取。 - ❌ 不适合用在需要清晰 API 文档结构和严格验证的情况(如 RESTful 接口层次设计),因 OpenAPI 无法详细标注嵌套路径语义。
- ✅ 推荐搭配路径校验逻辑一起使用,以避免非法路径访问问题(如目录穿越
../)。
路径参数校验
在 FastAPI 中,路径参数(Path Parameters) 是 URL 路径中的一部分(如 /items/{item_id}),它们用于标识资源。FastAPI 支持通过 Path() 函数对这些参数进行数值校验,包括设置范围限制、元信息、别名等。这样可以在请求到达业务逻辑前,确保参数满足预期的格式和数值要求。
重要特征:
- 绑定路径与函数参数:
路径参数在 URL 中直接体现,必须与函数参数名保持一致。 - 类型自动转换:
FastAPI 根据函数参数的类型注解自动将字符串路径参数转换为对应的数值类型(如int,float)。 - 数值范围校验:
使用Path()提供的ge(大于等于)、le(小于等于)、gt、lt参数进行数值限制。 - 元数据描述:
可以为路径参数添加title、description等元信息,自动出现在 Swagger UI 中。 - 自动生成文档和校验错误信息:
参数错误会返回 422 错误响应,API 文档会自动列出校验规则。
分页ID校验
路径参数校验
路径参数总是必需的,因为它必须是路径的一部分。所以,应该在声明时使用
...将其标记为必需参数。即使用None声明路径参数或设置一个其他默认值也不会有任何影响,它依然会是必需参数。
现象:
一个博客系统中通过 /posts/{page} 请求分页内容,为防止访问非法页数,使用 Path() 限制 page 必须大于等于 1。
特征对比:
- ✅ 路径参数:
page出现在 URL 中; - ✅ 类型转换:声明为
int; - ✅ 数值限制:使用
ge=1限制页码最小值; - ✅ 文档描述清晰:Swagger 中展示
page >= 1; - ✅ 错误捕捉自动化:非法页码(如 0)请求将返回 422
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(item_id: int = Path(..., ge=1, title="Item ID")): # ge是数值校验,title是元数据
return {"item_id": item_id}
参数排序
「按需对参数排序」 是指在定义路径操作函数时,参数的声明顺序可以根据需要进行调整,而不影响 FastAPI 对参数的解析和处理。这主要得益于 FastAPI 通过参数的名称、类型注解以及默认值声明(如 Query、Path 等)来识别参数类型,而非依赖其在函数中的位置。
在 Python 中,函数参数的顺序通常需要遵循:位置参数在前,默认参数在后。然而,在 FastAPI 中,由于其依赖于参数的类型注解和默认值来解析请求数据,因此参数的声明顺序可以根据开发者的需求进行调整,而不影响应用的功能。
重要特征:
- 参数顺序灵活:FastAPI 允许开发者根据需要调整函数参数的顺序,无需严格遵循位置参数和默认参数的传统顺序。
- 依赖类型注解解析:FastAPI 通过参数的类型注解(如
Query、Path)来识别参数类型,而非依赖其在函数中的位置。 - 兼容 Python 语法规则:尽管 FastAPI 提供了参数顺序的灵活性,但仍需遵守 Python 的语法规则,例如,位置参数不能跟在默认参数后面。
调整顺序满足语法
现象:
在定义一个路径操作函数时,item_id 是一个路径参数,q 是一个必需的查询参数。由于 item_id 使用了默认值(通过 Path 声明),而 q 没有默认值,直接将 q 放在 item_id 之后会违反 Python 的语法规则。为解决此问题,可以使用 * 将所有参数声明为关键字参数,从而允许 q 出现在 item_id 之后。
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(*, item_id: int = Path(..., title="The ID of the item to get"), q: str):
return {"item_id": item_id, "q": q}
特征对比:
- ✅ 参数顺序灵活:通过使用
*,允许q出现在item_id之后,满足 Python 的语法规则。 - ✅ 类型注解明确:
item_id使用Path声明,q是一个必需的查询参数,FastAPI 能正确解析。
使用Annotated提高清晰度
现象:
使用 Python 3.9+ 的 Annotated 类型注解,可以将参数的类型和元数据(如校验规则)结合在一起,使代码更清晰。
from typing import Annotated
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(..., title="The ID of the item to get")],
q: Annotated[str, Query(..., min_length=3)]
):
return {"item_id": item_id, "q": q}
特征对比:
- ✅ 参数声明清晰:使用
Annotated将类型和元数据结合,提升代码可读性。 - ✅ 顺序无关紧要:FastAPI 能正确解析参数,无论其在函数中的顺序如何。
数值校验
声明数值校验:
gt:大于(greaterthan)ge:大于等于(greater than orequal)lt:小于(lessthan)le:小于等于(less than orequal)
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
*,
item_id: int = Path(title="The ID of the item to get", gt=0, le=1000),
q: str,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
2.查询参数
查询参数
查询参数(Query Parameters)是在 Web API 请求中,通过 URL ? 后附加的键值对,用于向服务器端传递额外的数据,多个查询参数使用&隔开。FastAPI 会自动根据函数参数的声明将这些查询参数提取并转换为相应的数据类型,从而简化接口开发。
重要特征:
- 隐式解析机制:
FastAPI 自动识别路径中未声明为路径参数的函数参数为查询参数,无需显式标注。 - 类型转换与验证:
查询参数支持 Python 类型注解,FastAPI 会自动进行类型转换,并在请求验证失败时返回 422 错误。 - 默认值支持与可选性:
通过为参数指定默认值实现参数的可选性;无默认值时则为必填参数。 - 文档自动生成:
查询参数的信息(名称、类型、默认值)会自动出现在交互式 API 文档(Swagger UI)中。
分页页码与数量(正例)
查询参数
现象:
在一个博客系统中,客户端请求:GET /posts?skip=20&limit=10,用于控制返回第 3 页的 10 条文章。这些参数是 URL 中的查询参数。
特征对比:
- ✅ 隐式解析:
skip和limit都未出现在路径中,FastAPI 自动识别为查询参数; - ✅ 类型转换:声明为
int,若请求为字符串"20"也会被自动转换; - ✅ 默认值支持:可设置默认值使其成为可选参数;
- ✅ 文档可见性:在自动生成的 OpenAPI 文档中显示参数详情。
错误用路劲参数(反例)
查询参数
现象:
API 设计为 /users/admin/items 来获取管理员的物品,而不是使用 /users/items?role=admin 这样的查询参数设计。
特征对比(不一致处):
- ❌ 未使用查询参数机制:将变化频繁的数据(角色)放入了路径,不符合“附加控制信息用查询参数”的设计理念;
- ❌ 缺失类型转换与验证机制:路径参数不能像查询参数一样拥有复杂的验证逻辑(如布尔解析);
- ❌ 不利于可选参数设计:路径参数无法设置默认值,灵活性差;
- ❌ 文档结构不合理:路径结构因业务字段变化变得冗余,文档中路由增多,难以维护。
特征例子
查询参数
概念重要特征中的,「默认值」,「可选参数(默认值为None)」,「类型装换」,「必选参数(只有类型,没有默认值)」
类型转换:当fuzzy=1/true/True/on/yes其中任意大小写形式(大写、首字母大写等),函数接收的 fuzzy 参数都是布尔值 True。值为 False 时也一样。
必选参数:在@app.get("/search/")中q查询参数没有默认值,为「必选参数」。
from fastapi import FastAPI
app = FastAPI()
@app.get("/search/")
async def search_items(q: str, fuzzy: bool = False): # fuzzy支持默认值。
return {"query": q, "use_fuzzy": fuzzy}
@app.get("/items/{item_id}")
async def read_item(item_id: str, q: str | None = None): # q为可选参数
if q:
return {"item_id": item_id, "q": q}
return {"item_id": item_id}
路劲查询组合(正例)
查询参数
FastAPI 可以识别同时声明的多个路径参数和查询参数。而且声明查询参数的顺序并不重要。FastAPI 通过参数名进行检测:
from fastapi import FastAPI
app = FastAPI()
@app.get("/users/{user_id}/items/{item_id}")
async def read_user_item(
user_id: int, item_id: str, q: str | None = None, short: bool = False
): #路劲参数与查询参数的组合
item = {"item_id": item_id, "owner_id": user_id}
if q:
item.update({"q": q})
if not short:
item.update(
{"description": "This is an amazing item that has a long description"}
)
return item
查询参数校验
在 FastAPI 中,查询参数是 URL 中 ? 后的键值对,用于向服务器传递附加信息。通过 Query 类,开发者可以为这些参数添加额外的校验规则和元数据信息,从而增强 API 的数据验证能力和文档清晰度。
重要特征:
- 灵活的参数声明:使用
Query可以声明参数的默认值、是否为必需参数,以及其他校验规则。 - 字符串长度校验:可以通过
min_length和max_length限制字符串参数的长度。 - 正则表达式匹配:使用
regex参数,可以确保字符串参数符合特定的格式。 - 元数据设置:可以为参数添加标题、描述等元数据信息,提升自动生成文档的可读性。
- 参数别名与弃用:支持为参数设置别名(
alias)以及标记参数为弃用(deprecated)。
搜索查询参数校验(正例)
查询参数校验
现象:
在一个电商平台的搜索接口中,用户可以通过查询参数 q 提供搜索关键词。为了确保搜索效率和结果的相关性,限制关键词的长度在 3 到 50 个字符之间。
特征对比:
- ✅ 字符串长度校验:使用
min_length=3和max_length=50限制关键词长度。 - ✅ 参数声明:通过
Query明确声明参数的校验规则。 - ✅ 文档清晰度:在自动生成的文档中,清晰展示参数的校验信息。
多种校验(正例)
查询参数校验
- 导入Query
- 使用Query作为默认值,显式地将其声明为查询参数。
- 参数设定:
default为默认值,max_length参数设置为 50,添加min_length参数,定义一个参数值必须匹配的正则表达式pattern参数。 - 必须参数:Query不设定默认值。或者可以接收None值的参数。
from typing import Union
from fastapi import FastAPI, Query # 导入Query
app = FastAPI()
@app.get("/items/")
async def read_items(
q: Union[str, None] = Query(
default=None, min_length=3, max_length=50, pattern="^fixedquery$"
),
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
# 设定为必须参数,Query没有设定默认值
@app.get("/items/")
async def read_items(q: str = Query(min_length=3)):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
# 设定接收None的必选参数
@app.get("/items/")
async def read_items(q: Union[str, None] = Query(min_length=3)):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
查询参数列表
查询参数校验
接收同一个参数的多个值,还可以设定默认值。
from typing import List, Union
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(q: Union[List[str], None] = Query(default=["foo", "bar"])):
query_items = {"q": q}
return query_items
如果访问URL为http://localhost:8000/items/?q=foo&q=bar
响应内容为:
{
"q": [
"foo",
"bar"
]
}
也可以使用list替代List[str],在这种情况下 FastAPI 将不会检查列表的内容。例如,List[int] 将检查(并记录到文档)列表的内容必须是整数。但是单独的 list 不会。
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(q: list = Query(default=[])):
query_items = {"q": q}
return query_items
声明元数据
查询参数校验
- 添加title
- 添加description
- 别名参数
/items/?item-query=foobaritems想要的查询参数为item-query,但不是一个有效的 Python 变量名称。最接近的有效名称是item_query。但是仍然要求它在 URL 中必须是item-query。这时你可以用alias参数声明一个别名,该别名将用于在 URL 中查找查询参数值。 - 弃用参数:不再喜欢此参数,又不得不将其保留一段时间,因为有些客户端正在使用它,但希望文档清楚地将其展示为已弃用。
from typing import Union
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
q: Union[str, None] = Query(
default=None,
title="Query string", # 添加title
description="Query string for the items to search in the database that have a good match", # 添加描述
min_length=3,
alias="item-query", # 添加别名
deprecated=True, # 弃用参数
),
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
作用
查询参数校验作用
- 设计更稳定的接口规范
决策点:是否需要限制前端传入参数的范围、格式和合法性?
- 通过
min_length、max_length等校验机制,你可以明确告诉前端参数应当满足什么规范,从而防止无效输入导致程序异常。
2. 提升数据质量与业务正确性
决策点:如何确保进入业务逻辑的参数都是可信且合规的? - 在请求进入业务处理前自动校验参数,防止业务层处理非法输入。
- 提升接口安全性
决策点:是否需要防止参数注入、滥用或资源攻击?
- 对参数长度、字符集等进行限制,可以减缓 DDoS 或 SQL 注入等攻击的风险。
4. 优化前后端协作与自动文档生成
决策点:如何提高前端开发者理解 API 的效率? - 校验信息自动出现在 Swagger UI 中(比如参数是必填、最小长度是多少),前端无需反复问接口规范。
5. 判断参数设计的合理性与结构化程度
决策点:某些参数是否应作为路径参数、查询参数还是请求体? - 学会使用校验后,开发者能更清楚地知道:查询参数适用于控制信息和轻量数据,且可以独立验证,不适合放复杂结构。
查询参数模型
在 FastAPI 中,查询参数模型是指通过 Pydantic 的 BaseModel 将多个查询参数(Query Parameters)组织为一个结构化模型的方式。这种做法增强了可读性、可维护性,适用于查询参数较多且逻辑相关的情况。
FastAPI 自动识别函数参数类型为 BaseModel 的类,并将请求中的查询参数映射为模型中的字段,进行类型转换与验证,同时自动生成交互式 API 文档。
重要特征:
- 结构清晰:多个查询参数聚合为模型结构,避免多个函数参数分散定义。
- 自动验证:参数类型与约束通过 Pydantic 自动校验。
- 与请求体不同:查询参数出现在 URL 中(
?key=value),模型仅用于收集查询信息而非请求体数据。 - 文档自动生成:自动在 API 文档中生成查询字段的描述、类型和验证信息。
- 适合可选参数:支持默认值、可选字段与嵌套模型,便于构建灵活查询接口。
图书高级筛选
查询参数模型
现象
一个图书检索平台支持用户根据书名、作者、出版年、标签等条件进行筛选。后端通过 BookQuery 模型将这些参数打包,接收如 /search?author=Orwell&year=1949&tag=dystopia 的请求。
特征对比
- 结构清晰 ✔:所有查询条件封装在
BookQuery模型中 - 自动验证 ✔:年份是整数、标签是字符串列表,格式严格
- 查询参数位置正确 ✔:数据都在 URL 查询字符串中
- 适合多参数情况 ✔:避免多个独立函数参数,提升可读性
from fastapi import FastAPI, Depends
from pydantic import BaseModel
from typing import Optional
app = FastAPI()
class BookQuery(BaseModel):
author: Optional[str] = None
year: Optional[int] = None
tag: Optional[str] = None
@app.get("/books/")
def search_books(params: BookQuery = Depends()):
return {"query": params}
禁止额外查询参数
查询参数模型
在一些特殊的使用场景中(可能不是很常见),可能希望限制你要接收的查询参数。可以使用 Pydantic 的模型配置来 forbid(意为禁止 )任何 extra(意为额外的)字段:
from typing import Annotated, Literal
from fastapi import FastAPI, Query
from pydantic import BaseModel, Field
app = FastAPI()
class FilterParams(BaseModel):
model_config = {"extra": "forbid"} # 禁止额外参数
limit: int = Field(100, gt=0, le=100)
offset: int = Field(0, ge=0)
order_by: Literal["created_at", "updated_at"] = "created_at"
tags: list[str] = []
@app.get("/items/")
async def read_items(filter_query: Annotated[FilterParams, Query()]):
return filter_query
假设有一个客户端尝试在查询参数中发送一些额外的数据,它将会收到一个错误响应。
例如,如果客户端尝试发送一个值为 plumbus 的 tool 查询参数,如:
https://example.com/items/?limit=10&tool=plumbus
将收到一个错误响应,告诉他们查询参数 tool 是不允许的。
{
"detail": [
{
"type": "extra_forbidden",
"loc": ["query", "tool"],
"msg": "Extra inputs are not permitted",
"input": "plumbus"
}
]
}
电商下单接口(反例)
查询参数模型
现象:
一个电商平台将下单数据(商品 ID、购买数量、用户地址)以查询参数方式传递:/order?item_id=123&quantity=2&address=Beijing,后端尝试用查询参数模型处理。
特征对比
- 不适合使用位置 ✘:下单应使用请求体提交数据,而不是查询参数(应是 POST 请求体)
- 数据结构复杂 ✘:地址等信息应以结构化体数据而非 URL 查询
- 违反语义 ✘:GET/查询模型应仅用于读取,不用于创建资源
- 可扩展性差 ✘:添加更多字段会让 URL 冗长且不安全
3.Cookie参数
Cookie参数
Cookie 参数 是通过 Request 或 Cookie 类来接收请求中的 cookie 值。这些参数通常用于存储会话信息、用户偏好设置或认证标记等,在客户端和服务器之间传递小量数据。与查询参数、路径参数等不同,Cookie 参数是存储在浏览器的 Cookie 中,并且由浏览器自动随请求发送给服务器。
FastAPI 使用 Cookie 类来处理 cookie 参数,并且可以在路由函数中直接获取这些参数值。它还支持为 cookie 设置默认值、过期时间等属性。
重要特征:
- 自动传递:浏览器会自动在每个请求中携带相关的 cookie 值,开发者无需手动传递。
- 存储小数据:cookie 的大小通常有限制,适合存储少量的用户信息(如用户 ID、认证 token 等)。
- 跨请求保持状态:通过 cookie,服务器能够在不同的请求之间保持状态,常用于实现会话管理和用户认证。
- 简化认证流程:通过 cookie,可以实现如 JWT 等认证方式,使得用户无需每次请求时手动传递认证信息。
- 隐式传递:cookie 在每次请求时由浏览器自动携带,无需显式传递在请求中。
细节
Cookie细节
Cookie、Path、Query是兄弟类,都继承自共用的Param类。- 注意,从
fastapi导入的Query、Path、Cookie等对象,实际上是返回特殊类的函数。 - 必须使用
Cookie声明 cookie 参数,否则该参数会被解释为查询参数。
用户登录状态管理(正例)
Cookie参数
现象:
在一个电商网站中,用户登录后服务器生成了一个会话 ID,并将其存储在浏览器的 cookie 中。每次用户访问页面时,浏览器会自动携带该 cookie,以便服务器验证用户身份。
特征对比:
- 自动传递 ✔:浏览器会自动携带存储在 cookie 中的会话 ID。
- 跨请求保持状态 ✔:服务器根据 cookie 中的会话 ID 来判断用户的登录状态,避免每次请求都需要重新认证。
- 简化认证流程 ✔:用户无需每次输入用户名和密码,浏览器会自动发送包含认证信息的 cookie。
from fastapi import FastAPI, Cookie, HTTPException
app = FastAPI()
@app.get("/profile/")
def read_profile(session_id: str = Cookie(None)):
if session_id is None:
raise HTTPException(status_code=401, detail="User not authenticated")
return {"session_id": session_id}
用户个性化设置(正例)
Cookie参数
现象:
某网站允许用户设置界面语言偏好,用户选择语言后,系统会通过 cookie 保存该选择,每次用户访问该网站时,浏览器会自动携带 cookie,系统根据该 cookie 来加载相应语言的页面。
特征对比
- 存储小数据 ✔:语言设置是一个小的值,可以通过 cookie 存储。
- 自动传递 ✔:浏览器会自动携带存储语言偏好的 cookie 信息。
- 跨请求保持状态 ✔:用户在登录后每次访问时,系统根据 cookie 自动应用用户的语言设置,保持一致的用户体验。
from fastapi import FastAPI, Cookie
app = FastAPI()
@app.get("/language/")
def get_language(preferred_language: str = Cookie("en")):
return {"preferred_language": preferred_language}
购物车(反例)
Cookie参数
现象:
在某电商平台上,用户的购物车信息保存在 cookie 中。由于购物车数据较大,cookie 存储的信息超出了限制,导致无法正常传递购物车信息。
特征对比:
- 存储小数据 ✘:购物车数据量大,无法通过 cookie 存储。
- 自动传递 ✘:由于数据量过大,浏览器无法正常携带所有购物车信息,导致部分信息丢失。
- 跨请求保持状态 ✘:由于 cookie 数据量限制,无法实现跨请求的有效数据传递,影响购物车功能的正常工作。
Cookie参数模型
Cookie参数模型是FastAPI中通过Pydantic模型来统一管理和验证HTTP Cookie参数的机制。它允许开发者将多个相关的Cookie参数组织成一个结构化的数据模型,实现自动解析、类型转换、数据验证和序列化,提供类型安全的Cookie处理方式。
重要特征:
- 结构化组织:将多个相关Cookie参数封装在单一Pydantic模型中,提供清晰的数据结构
- 自动类型转换:根据模型字段类型自动将Cookie字符串值转换为相应的Python数据类型
- 数据验证:利用Pydantic验证器对Cookie值进行格式、范围等约束检查
- 类型安全:提供IDE自动补全和静态类型检查支持
- 统一接口:通过单一模型对象访问所有相关Cookie参数
用户偏好设置管理(正例)
在电商网站中,使用Cookie参数模型管理用户的个性化偏好设置,包括语言选择、货币类型、商品展示方式等多个相关配置项。在特殊情况下,可以forbid来限制想接收的参数。
特征对比:
- ✓ 结构化组织:将language、currency、display_mode等相关偏好封装在UserPreferences模型中
- ✓ 自动类型转换:将Cookie字符串"zh-CN"转换为枚举类型,"10"转换为整数
- ✓ 数据验证:验证语言代码格式、货币类型有效性、显示模式范围
- ✓ 类型安全:模型提供明确的字段类型定义
- ✓ 统一接口:通过preferences.language访问所有偏好设置
from typing import Annotated
from fastapi import Cookie, FastAPI
from pydantic import BaseModel, Field
from enum import Enum
app = FastAPI()
class Language(str, Enum):
CHINESE = "zh-CN"
ENGLISH = "en-US"
JAPANESE = "ja-JP"
class Currency(str, Enum):
CNY = "CNY"
USD = "USD"
JPY = "JPY"
class UserPreferences(BaseModel): # 声明Cookie参数模型
model_config = {"extra":"forbid"} # 禁止「extra」字段
language: Language = Field(default=Language.CHINESE, description="用户语言偏好")
currency: Currency = Field(default=Currency.CNY, description="货币类型")
items_per_page: int = Field(default=20, ge=10, le=100, description="每页商品数量")
dark_mode: bool = Field(default=False, description="是否启用暗色主题")
@app.get("/user/dashboard")
async def get_dashboard(preferences: Annotated[UserPreferences, Cookie()]):
return {
"message": f"欢迎访问,您的偏好设置为:",
"preferences": {
"language": preferences.language.value,
"currency": preferences.currency.value,
"items_per_page": preferences.items_per_page,
"dark_mode": preferences.dark_mode
}
}
# 运行示例
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
4.Header参数
Hedaer参数
Header 参数是指通过请求头(HTTP headers)传递的参数。请求头包含了请求的元数据和一些附加信息,FastAPI 允许开发者通过声明函数参数,自动提取这些请求头的内容。常见的头部信息包括认证信息(如 Authorization)、内容类型(如 Content-Type)、用户代理(如 User-Agent)等。通过使用 FastAPI 的 Header 参数模型,可以轻松从请求头中提取数据并进行进一步处理和验证。
重要特征:
- 自动提取:FastAPI 能够从 HTTP 请求头中自动提取相应的参数,并将其作为函数参数传递给请求处理函数。
- 类型验证:开发者可以为请求头参数指定类型,FastAPI 会自动进行类型验证和转换,确保数据格式正确。
- 默认值支持:如果请求头中缺少指定的参数,FastAPI 会使用参数的默认值(如果有设置),避免程序崩溃或返回错误。
API请求认证(正例)
现象:
在一个需要身份验证的 RESTful API 中,客户端每次请求都需要在 Authorization 头部传递一个 token。后端通过 Header 参数模型提取该 Authorization 信息并进行验证。如果 token 验证成功,后端将处理请求;否则返回认证失败的响应。
特征对比
- 自动提取:FastAPI 自动从请求头的
Authorization字段提取 token,开发者无需手动解析请求头。 - 类型验证:可以为
Authorization头部字段设置类型(如str),确保传递的 token 为有效字符串。 - 默认值支持:如果没有提供
Authorization头部,FastAPI 可以返回默认值或者处理错误,避免程序异常。
from fastapi import FastAPI, Header, HTTPException
app = FastAPI()
@app.get("/profile")
async def get_profile(authorization: str = Header(...)):
if authorization != "Bearer valid_token":
raise HTTPException(status_code=401, detail="Invalid token")
return {"message": "Profile data"}
获取代理(正例)
大部分标准请求头用连字符分隔,即减号(-)。但是 user-agent 这样的变量在 Python 中是无效的。因此,默认情况下,Header 把参数名中的字符由下划线(_)改为连字符(-)来提取并存档请求头 。
同时,HTTP 的请求头不区分大小写,可以使用 Python 标准样式(即 snake_case)进行声明。因此,可以像在 Python 代码中一样使用 user_agent ,无需把首字母大写为 User_Agent 等形式。
如需禁用下划线自动转换为连字符,可以把 Header 的 convert_underscores 参数设置为 False
注意,使用 convert_underscores = False 要慎重,有些 HTTP 代理和服务器不支持使用带有下划线的请求头。
from typing import Annotated
from fastapi import FastAPI, Header
app = FastAPI()
@app.get("/items/")
async def read_items(
strange_header: Annotated[str | None, Header(convert_underscores=False)] = None,
):
return {"strange_header": strange_header}
重复请求头(正例)
有时可能需要接收重复的请求头。即同一个请求头有多个值。类型声明中可以使用 list 定义多个请求头。使用 Python list 可以接收重复请求头所有的值。例如,声明 X-Token 多次出现的请求头,可以写成这样:
from typing import Annotated
from fastapi import FastAPI, Header
app = FastAPI()
@app.get("/items/")
async def read_items(x_token: Annotated[list[str] | None, Header()] = None):
return {"X-Token values": x_token}
HTTP请求:
X-Token: foo
X-Token: bar
响应结果:
{
"X-Token values": [
"bar",
"foo"
]
}
Header参数模型
Header 参数模型是 FastAPI 提供的一种功能,允许在 API 接口中通过 HTTP 请求头部(Headers)传递数据,并能将这些请求头部内容自动解析为 Python 类型。FastAPI 能够自动将请求头中的数据与开发者定义的模型进行匹配,并将解析的结果传递给对应的视图函数。
重要特征:
- 类型验证:通过定义 Pydantic 模型,可以确保传入的请求头符合特定的数据结构和类型要求。
- 文档自动生成:FastAPI 能根据模型自动生成 API 文档,客户端可以直接查看请求头中应包含哪些字段及其类型。
- 灵活性与扩展性:支持通过
Header类灵活定义请求头参数,能够处理基本的 Header 传递,也能适应复杂场景。
OAuth2认证Header
Header参数模型
现象:在一个认证系统中,使用 Authorization 请求头传递 Token,用于身份验证和权限控制。开发者可以通过 FastAPI 的 Header 参数模型,提取 Authorization 信息,并进行 Token 验证。
特征对比:
- 类型验证:通过 FastAPI 的 Pydantic 模型,开发者可以确保请求头中的 Authorization 字段符合规范。
- 文档自动生成:API 文档会自动展示如何传递 Authorization 请求头,用户可以清楚地知道需要提供什么数据。
- 灵活性与扩展性:允许开发者根据实际需求进行 Token 解析和处理,不局限于简单的验证。
from fastapi import FastAPI, Header
from pydantic import BaseModel
app = FastAPI()
class TokenHeader(BaseModel):
authorization: str
@app.get("/items/")
async def read_items(token: TokenHeader = Header(...)):
return {"token": token.authorization}
获取Header中的参数
from typing import Annotated
from fastapi import FastAPI, Header
from pydantic import BaseModel
app = FastAPI()
class CommonHeaders(BaseModel): # 声明所需Header参数
host: str
save_data: bool
if_modified_since: str | None = None
traceparent: str | None = None
x_tag: list[str] = []
@app.get("/items/")
async def read_items(headers: Annotated[CommonHeaders, Header()]): # 将参数声明为Header
return headers
静止额外参数
在某些特殊使用情况下(可能并不常见),您可能希望限制您想要接收的 headers。
可以使用 Pydantic 的模型配置来禁止(forbid)任何额外(extra)字段
from typing import Annotated
from fastapi import FastAPI, Header
from pydantic import BaseModel
app = FastAPI()
class CommonHeaders(BaseModel):
model_config = {"extra": "forbid"} # 禁止'extra'参数
host: str
save_data: bool
if_modified_since: str | None = None
traceparent: str | None = None
x_tag: list[str] = []
@app.get("/items/")
async def read_items(headers: Annotated[CommonHeaders, Header()]):
return headers
5.响应参数
响应模型
响应模型(Response Model)是 FastAPI 用来对 API 返回结果进行验证和格式化的功能。通过响应模型,开发者可以定义返回数据的结构、类型及其格式,确保返回的数据符合预期,同时通过 Pydantic 模型自动进行数据验证。
使用_路径操作装饰器_的
response_model参数来定义响应模型,特别是确保私有数据被过滤掉。使用response_model_exclude_unset来仅返回显式设定的值。
「装饰器」方法(
get,post等)的一个参数。不像之前的所有参数和请求体,它不属于_路径操作函数_。
响应模型在参数中被声明,而不是作为函数返回类型的注解,这是因为路径函数可能不会真正返回该响应模型,而是返回一个
dict、数据库对象或其他模型,然后再使用response_model来执行字段约束和序列化。
重要特征:
- 类型验证:响应模型使用 Pydantic 模型确保返回的数据符合预定义的数据类型和格式。
- 自动文档生成:基于响应模型,FastAPI 自动生成 API 文档,并清晰地展示接口返回的数据结构,帮助客户端开发者理解返回值的类型和意义。
- 数据格式化:开发者可以通过模型对数据进行额外的格式化,比如设置字段别名、默认值、字段忽略等。
- 增强可读性:通过响应模型,API 的响应数据结构更加清晰,易于维护和扩展,增强了接口的可读性和一致性。
返回用户信息
响应模型
创建一个有明文密码的输入模型和一个没有明文密码的输出模型,FastAPI 将会负责过滤掉未在输出模型中声明的所有数据(使用 Pydantic)。
from typing import Any
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
app = FastAPI()
class UserIn(BaseModel):
username: str
password: str
email: EmailStr
full_name: str | None = None
class UserOut(BaseModel):
username: str
email: EmailStr
full_name: str | None = None
@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn) -> Any:
return user
响应参数默认值
响应模型
response_model_exclude_unset=True参数,表示是否排除哪些未设置的默认值字段(哪些没有显示传入的字段)。当 response_model_exclude_unset=True 时,FastAPI 会从响应中排除那些在响应数据模型中设置了默认值,但实际响应中没有提供的字段。这对于优化响应数据、减少不必要的冗余非常有用,尤其是在需要返回较大或复杂的模型时。
from typing import List, Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None # 默认值为None
price: float
tax: float = 10.5 # 默认值10.5
tags: List[str] = [] # 默认值[]
items = {
"foo": {"name": "Foo", "price": 50.2},
"bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
"baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}
@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
return items[item_id]
- 访问
foo时,响应不包括默认值:
{
"name": "Foo",
"price": 50.2
}
- 访问
bar时,访问的数据在「具有默认值的模型字段」中有实际值,这些值将会包含在响应中。
{
"name": "Bar",
"description": "The bartenders",
"price": 62,
"tax": 20.2
}
- 访问
baz,实际值与默认值相同,将会被「显示的设定」而不是「取默认值」。
{
"name": "Baz",
"description": None,
"price": 50.2,
"tax": 10.5,
"tags": []
}
增减响应数据
响应模型
使用_路径操作装饰器_的
response_model_include和response_model_exclude参数。
它们接收一个由属性名称
str组成的set来包含(忽略其他的)或者排除(包含其他的)这些属性。
如果只有一个 Pydantic 模型,并且想要从输出中移除一些数据,则可以使用这种快捷方法。
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: float = 10.5
items = {
"foo": {"name": "Foo", "price": 50.2},
"bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2},
"baz": {
"name": "Baz",
"description": "There goes my baz",
"price": 50.2,
"tax": 10.5,
},
}
@app.get(
"/items/{item_id}/name",
response_model=Item,
response_model_include={"name", "description"},
)
async def read_item_name(item_id: str):
return items[item_id]
@app.get("/items/{item_id}/public", response_model=Item, response_model_exclude={"tax"}) # 删除tax元素
async def read_item_public_data(item_id: str):
return items[item_id]
返回响应列表
响应模型
声明由对象列表构成的响应。
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str
items = [
{"name": "Foo", "description": "There comes my hero"},
{"name": "Red", "description": "It's my aeroplane"},
]
@app.get("/items/", response_model=list[Item])
async def read_items():
return items
可选响应类型
响应模型
响应可以声明为两种类型的
Union类型,即该响应可以是两种类型中的任意类型。
定义
Union类型时,要把详细的类型写在前面,然后是不太详细的类型。下例中,更详细的PlaneItem位于Union[PlaneItem,CarItem]中的CarItem之前。
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class BaseItem(BaseModel):
description: str
type: str
class CarItem(BaseItem):
type: str = "car"
class PlaneItem(BaseItem):
type: str = "plane"
size: int
items = {
"item1": {"description": "All my friends drive a low rider", "type": "car"},
"item2": {
"description": "Music is my aeroplane, it's my aeroplane",
"type": "plane",
"size": 5,
},
}
@app.get("/items/{item_id}", response_model=Union[PlaneItem, CarItem])
async def read_item(item_id: str):
return items[item_id]
6.响应状态码
响应状态码是 HTTP 协议中的一个重要组成部分,用于表示服务器对请求的处理结果。在 FastAPI 中,开发者可以通过路径操作装饰器自定义响应的状态码。默认情况下,FastAPI 根据 HTTP 请求的类型(如 GET、POST、PUT、DELETE 等)自动为响应设置适当的状态码,但开发者也可以显式地指定一个响应状态码,以便更精确地控制 API 的响应行为。
常见的 HTTP 状态码包括:
- 1xx:用于返回信息。这类状态码很少直接使用。具有这些状态码的响应不能包含响应体
- 2xx:成功类状态码(例如
200 OK表示请求成功,201 Created表示资源创建成功) - 3xx:用于重定向。具有这些状态码的响应不一定包含响应体,但
304未修改是个例外,该响应不得包含响应体 - 4xx:客户端错误类状态码(例如
400 Bad Request表示请求格式不正确,404 Not Found表示资源未找到) - 5xx:服务器错误类状态码(例如
500 Internal Server Error表示服务器发生错误)
重要特征:
- 状态码自定义:通过 FastAPI,开发者可以自定义响应的状态码,适应不同场景。
- 自动状态码推断:对于常见的 HTTP 请求方法(如 GET、POST),FastAPI 自动为响应分配默认状态码。
- 清晰的状态传递:正确的状态码传递可以帮助客户端准确理解请求的结果(成功、失败、错误类型等)。
- 适应不同场景:状态码根据不同的请求和响应情境,灵活调整,例如对于资源创建、修改、删除等操作,常使用
201 Created或204 No Content。
status
使用 fastapi.status 中的快捷变量。
from fastapi import FastAPI, status
app = FastAPI()
@app.post("/items/", status_code=status.HTTP_201_CREATED)
async def create_item(name: str):
return {"name": name}
7.解包与模型继承
解包dict
通过 Python 的解包操作符 **,将字典(dict)的键值对解构并传递给函数或模型。这使得我们可以将字典数据直接传递给 FastAPI 路由函数或者 Pydantic 模型实例,从而简化代码并提升代码的灵活性和可读性。
FastAPI 利用解包字典功能来实现动态地传递参数,特别是在处理请求数据或构造 API 响应时,避免手动逐一传递参数。通过这种方式,可以直接将一个字典作为函数参数传递,避免冗长的手动赋值。
重要特征:
- 动态传递参数:可以动态将字典中的键值对传递给函数或模型,而不需要显式列出每个参数。
- 简化代码:通过解包字典,减少了手动逐个传递参数的需求,增强代码的简洁性和可读性。
- 增强灵活性:字典解包使得处理不同结构的数据变得更加灵活,尤其适合那些需要根据不同场景动态构建请求参数或响应数据的应用。
- 兼容 Pydantic 模型:可以将解包的字典直接传递给 Pydantic 模型,用于构建验证后的数据对象。
解包处理用户数据
解包dict
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class User(BaseModel):
username: str
email: str
age: int
@app.post("/users/")
async def create_user(user: User):
return {"message": f"User {user.username} created successfully", "user": user.dict()}
@app.get("/users/{user_id}")
async def get_user(user_id: int, user_data: dict):
# 使用字典解包
user = User(**user_data)
return {"user_id": user_id, "user": user.dict()}
解包与更多关键字
解包dict
继续添加关键字参数 hashed_password=hashed_password
UserInDB(**user_in.dict(), hashed_password=hashed_password)
# 输出结果
UserInDB(
username = user_dict["username"],
password = user_dict["password"],
email = user_dict["email"],
full_name = user_dict["full_name"],
hashed_password = hashed_password,
)
模型继承
在 FastAPI 中通过将共享的字段和验证逻辑定义在一个基类中,使得其他数据模型可以继承该基类,从而避免了重复定义相同的字段和验证规则。这种做法不仅提高了代码的重用性,还简化了数据模型的维护,使得修改和更新变得更加高效。
通过模型继承,开发者可以定义多个模型之间的差异,例如在某些模型中包含密码字段、在另一些模型中则只包含哈希后的密码或不包含密码。继承结构帮助开发者仅声明模型之间的差异部分,而不是每次都从头开始定义所有字段。
重要特征:
- 共享字段和验证逻辑:基类模型包含公共字段和验证逻辑,子类模型可以继承基类的所有功能,避免重复代码。
- 灵活的差异声明:通过继承,开发者可以灵活地声明模型之间的差异,只需在子类中增加或修改需要的字段,而不需要重复定义相同的字段。
- 简化代码:继承机制大大减少了代码冗余,使得代码更简洁、更易于维护。
- 支持数据转换与文档生成:FastAPI 会自动支持基类和子类的字段转换、验证以及自动生成 API 文档,无需额外的配置。
用户信息继承
模型继承
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
app = FastAPI()
class UserBase(BaseModel):
username: str
email: EmailStr
full_name: str | None = None
class UserIn(UserBase):
password: str
class UserOut(UserBase):
pass
class UserInDB(UserBase):
hashed_password: str
def fake_password_hasher(raw_password: str):
return "supersecret" + raw_password
def fake_save_user(user_in: UserIn):
hashed_password = fake_password_hasher(user_in.password)
user_in_db = UserInDB(**user_in.dict(), hashed_password=hashed_password)
print("User saved! ..not really")
return user_in_db
@app.post("/user/", response_model=UserOut)
async def create_user(user_in: UserIn):
user_saved = fake_save_user(user_in)
return user_saved