15. FastAPI 响应类型_列表格式
列表响应描述一组同类资源
JSON 顶层可以直接是数组,如 [{"id":1},{"id":2}]。list[ItemOut] 表示“列表中的每一项都符合 ItemOut”,而不是只检查列表外壳。
python
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class ItemOut(BaseModel):
id: int
name: str
tags: list[str] = []
@app.get("/items", response_model=list[ItemOut])
def list_items():
return [
{"id": 1, "name": "键盘", "tags": ["办公"], "cost": 80},
{"id": 2, "name": "鼠标", "tags": [], "cost": 30},
]
@app.get("/empty", response_model=list[ItemOut])
def empty_items():
return []保存为 main.py,运行 uv run uvicorn main:app --reload。/items 返回两个对象,内部成本 cost 被过滤;/empty 返回 []。列表为空通常是成功结果,不必使用 404。
本例列表默认值由 Pydantic 处理;在自己的普通 Python 函数或数据类中不要据此照搬可变默认参数,工程里也可以统一使用 Field(default_factory=list)。
裸数组还是封装对象
| 格式 | 优点 | 适合 |
|---|---|---|
[{...}] | 简单、客户端直接遍历 | 小型固定集合 |
{"items":[...],"total":100} | 可带总量、页码、游标 | 分页与长期演进 |
接口一旦对外使用,从数组改成对象会影响客户端,应提前决定协议。第 17 篇会实现可复用分页模型。
从数据库返回时的注意点
不要直接拿 SQLAlchemy 的 Row 当普通实体。查询实体常用 session.scalars(select(Item)).all();选择多列时常用 .mappings() 或明确转字典。Pydantic 读取 ORM 属性需要 ConfigDict(from_attributes=True)。
有关联关系时,输出嵌套模型可能触发额外数据库查询。应先选择加载策略,避免每个列表项都再查一次数据库。千万条记录不能因为声明了列表模型就一次性全部返回,应限制每次查询数量。
类型与输出契约
列表中的任何一个元素缺少必填字段,都可能让整个响应校验失败。这是服务端问题,应通过测试提前发现。直接返回生成器也不等于网络流式传输;逐块输出要使用 StreamingResponse 等流式响应。
练习:增加第三个商品,故意遗漏 name,观察服务端校验失败;修复后再测试空列表。为一个“城市字典”接口选择裸数组或封装对象,并说明理由。