在fastapi开发中,单个endpoint支持多种响应格式是提升接口灵活性的常见需求,比如同时支持json和csv格式返回数据,可以让接口适配不同场景的使用要求。

实现核心思路
要让单个endpoint支持json和csv两种响应格式,核心逻辑分为三步:
- 接收客户端传递的格式参数,比如通过查询参数
format指定返回格式 - 根据参数判断目标格式,对接口返回的原始数据进行对应格式的序列化处理
- 设置正确的响应头,告知客户端返回的数据类型,避免客户端解析错误
具体实现步骤
1. 定义基础数据和endpoint
首先我们定义一个简单的数据模型,以及一个返回原始数据的endpoint,后续在这个endpoint基础上扩展格式支持逻辑。
from fastapi import FastAPI, Query
from fastapi.responses import Response
from pydantic import BaseModel
from typing import List, Optional
import csv
import io
import json
app = FastAPI()
# 定义数据模型
class User(BaseModel):
id: int
name: str
age: int
# 模拟数据库查询得到的原始数据
def get_user_data() -> List[User]:
return [
User(id=1, name="张三", age=20),
User(id=2, name="李四", age=22),
User(id=3, name="王五", age=25)
]
2. 处理json格式响应
json格式是fastapi默认的响应格式,不需要额外做太多处理,只需要把数据转换为json字符串,设置对应的Content-Type即可。
def generate_json_response(data: List[User]) -> Response:
# 将数据转换为json字符串
json_data = json.dumps([user.dict() for user in data], ensure_ascii=False)
# 返回响应,设置Content-Type为application/json
return Response(
content=json_data,
media_type="application/json",
headers={"Content-Disposition": "attachment; filename=users.json"}
)
3. 处理csv格式响应
csv格式需要把数据转换为逗号分隔的文本,同时设置对应的Content-Type和文件下载头。
def generate_csv_response(data: List[User]) -> Response:
# 创建内存中的字符串流
output = io.StringIO()
# 创建csv写入器
writer = csv.writer(output)
# 写入表头
writer.writerow(["id", "name", "age"])
# 写入数据行
for user in data:
writer.writerow([user.id, user.name, user.age])
# 获取csv字符串
csv_data = output.getvalue()
output.close()
# 返回响应,设置Content-Type为text/csv
return Response(
content=csv_data,
media_type="text/csv",
headers={"Content-Disposition": "attachment; filename=users.csv"}
)
4. 整合到单个endpoint中
最后把格式判断逻辑和两种响应生成逻辑整合到同一个endpoint里,通过查询参数format控制返回格式,默认返回json格式。
@app.get("/users")
def get_users(format: Optional[str] = Query(default="json", description="返回格式,可选json或csv")):
# 获取原始数据
user_data = get_user_data()
# 根据format参数判断返回格式
if format == "csv":
return generate_csv_response(user_data)
else:
return generate_json_response(user_data)
测试验证
启动服务后,可以通过以下两种方式测试接口:
- 访问
http://127.0.0.1:8000/users?format=json,会返回json格式的用户数据 - 访问
http://127.0.0.1:8000/users?format=csv,会下载csv格式的用户数据文件
如果需要支持更多格式,只需要在endpoint里增加对应的格式判断分支,以及对应的响应生成函数即可,扩展起来非常方便。
注意事项
- csv格式处理时要注意中文编码问题,这里使用
ensure_ascii=False保证json里的中文正常显示,csv使用默认的utf-8编码,客户端下载后如果用Excel打开乱码,可以手动选择utf-8编码打开 - 响应头的
Content-Disposition设置为attachment会让浏览器直接下载文件,如果不需要下载只是展示,可以去掉这个头或者设置为inline - 如果接口返回的数据量很大,csv格式生成时要注意内存占用,可以考虑流式生成响应,避免一次性把所有数据加载到内存中