fastapi(65)- 路由函数指定了 response_model,在返回自定义 JSONResponse 时, 不会限制它返回的数据结构

简介: fastapi(65)- 路由函数指定了 response_model,在返回自定义 JSONResponse 时, 不会限制它返回的数据结构

前置知识


JSONResponse:https://www.cnblogs.com/poloyy/p/15364445.html

response_model:https://www.cnblogs.com/poloyy/p/15317585.html

 

背景


在写辣鸡平台,然后有统一的自定义 JSONResponse,所以全部路径函数都是返回自定义 JSONResponse 的,比如

@router.post("/save", response_model=UserResponse)
async def save(user_save: UserSave, db: Session = Depends(get_db)) -> JSONResponse:
    ...
    return SuccessResponse(message="123", data=123)
@router.post("/user_list", response_model=UserListResponse)
async def get_user_list(
    user_page: UserPage, db: Session = Depends(get_db)
) -> JSONResponse:
    ...
    return SuccessResponse(data=123)
@router.put("/active", response_model=BaseResponse)
async def active(
    id: int = Body(..., description="用户ID"),
    state: States = Body(default=States.ACTIVE, description="用户状态"),
    db: Session = Depends(get_db),
) -> JSONResponse:
    ...
    return SuccessResponse(message="123", data=123)


  • 这里的 SuccessResponse 就是继承 JSONResponse,是一个自定义响应对象
  • 然后也可以看到三个路径函数都指定了 response_model

 

问题来了

路由操作函数返回的是自定义 JSONResponse,同时指定了 response_model,按道理最后返回的响应数据应该被限制为 model 里面的数据才对,但实际并没有

 

为啥我会发现这个问题呢

  • 在我创建 user 之后,想返回整个 user 对象给前端,但自然而然 password 是不可以返回的,所以 response_model 就去掉这个 password 字段
  • 但最终返回的响应体仍然有 password 字段

 

重新演示一遍上述问题现象


fastapi 代码

from fastapi import FastAPI
import uvicorn
app = FastAPI()
class UserBase(BaseModel):
    username: str
    email: str
class UserCreate(UserBase):
    password: str
fake_db = []
# response_model 的 UserBase 只包含  username、email 没有 password
@app.post("/create", response_model=UserBase)
async def create(user: UserCreate):
    # 模拟:添加数据进数据库
    fake_db.append(user)
    # 模拟拿到完整的 user
    user = jsonable_encoder(user)
    return JSONResponse(status_code=200, content=user)
if __name__ == "__main__":
    uvicorn.run("test:app", port=8001, debug=True)


查看 OpenAPI 文档

image.png

因为添加了 response_model,所以 Responses 的 Example Value 是按照 response_model 的数据来生成的,就没有 password

 

发起请求,查看响应


image.png

但真实发送请求后,还是有 password 字段

 

return 字典代替 JSONResponse

@app.post("/create", response_model=UserBase)
async def create(user: UserCreate):
    # 模拟:添加数据进数据库
    fake_db.append(user)
    # 模拟拿到完整的 user
    user = jsonable_encoder(user)
    return user


再发起请求,查看响应

image.png

假设最终 return 的是一个字典,那么 response_model 就可以限制它的响应数据了,所以这里没有 password

 

根本原因


首先要记得 response_model 的作用

  • 将输出数据转换为 Model 中声明的类型
  • 验证数据
  • 在 OpenAPI 给 Response 添加 JSON Schema 和 Example Value
  • 最重要:将输出数据限制为 model 的数据

 

再来,在 return 那打个断点,Debug 分别看看两种 return 的场景

 

return user 断点

image.png

  • 断点后 F7 进入的就是这里
  • 在经过 fastapi 内部一长串各种调用处理后,response 本身包含 password 字段,但最后得到的 response_data 已经去掉了 password 字段
  • 得到这个 response_data 后,最后还是会将它赋值给 JSONResponse 的 content ,然后接口再返回给前端


image.png

return JSONResponse 断点

image.png

  • 断点后 F7 进入的就是这里
  • 和上面完全不一样,跳过了前面 fastapi 处理数据的一长串步骤
  • 因为这里是直接 return JSONResponse,所以 content 值已经确定了
  • 最后赋什么值,接口返回的就是什么,并不会受 response_model 的限制

 

那 return JSONResponse 还有必要设置  response_model 吗?

  • 如果是合作开发,还是有必要的,因为 response_model 可以自动添加 JSON Schema、Example Value 在 Swagger 文档中,可读性大大提升
  • 但它的作用也仅是提供 JSON Schema、Example Value
相关文章
|
1天前
|
存储 Java 开发者
如何在Java中实现自定义数据结构
如何在Java中实现自定义数据结构
|
7天前
|
存储 安全 Java
如何在Java中实现自定义数据结构:从头开始
如何在Java中实现自定义数据结构:从头开始
|
7天前
|
存储 JavaScript 前端开发
JavaScript中的对象是数据结构,存储键值对,键为字符串,值可为任意类型,包括函数(作为方法)
【6月更文挑战第25天】JavaScript中的对象是数据结构,存储键值对,键为字符串,值可为任意类型,包括函数(作为方法)。
11 2
|
26天前
|
存储 算法
数据结构学习记录——集合及运算(集合的表示、并查集、树结构表示集合、集合运算、查找函数、并运算)
数据结构学习记录——集合及运算(集合的表示、并查集、树结构表示集合、集合运算、查找函数、并运算)
8 0
|
26天前
数据结构学习记录——判断是否为同一颗二叉搜索树(题意理解、求解思路、程序搭建框架、具体函数的实现)
数据结构学习记录——判断是否为同一颗二叉搜索树(题意理解、求解思路、程序搭建框架、具体函数的实现)
17 2
|
26天前
|
算法
数据结构和算法学习记录——初识二叉树(定义、五种基本形态、几种特殊的二叉树、二叉树的重要性质、初识基本操作函数)
数据结构和算法学习记录——初识二叉树(定义、五种基本形态、几种特殊的二叉树、二叉树的重要性质、初识基本操作函数)
11 0
|
26天前
|
存储 算法
数据结构和算法学习记录——特殊线性表之队列-队列的概念、队列结构体类型定义 、基本接口函数、初始化函数、销毁队列函数、入队列函数、判断队列是否为空、出队列函数、读取队头队尾的数据 、计算队列数据个数
数据结构和算法学习记录——特殊线性表之队列-队列的概念、队列结构体类型定义 、基本接口函数、初始化函数、销毁队列函数、入队列函数、判断队列是否为空、出队列函数、读取队头队尾的数据 、计算队列数据个数
16 0
|
26天前
|
算法 C语言
数据结构和算法学习记录——特殊线性表之栈(下)-销毁栈函数、判断栈是否为空、压栈函数、出栈函数、取栈顶元素、计算栈中有多少个元素、栈有关习题-有效的括号
数据结构和算法学习记录——特殊线性表之栈(下)-销毁栈函数、判断栈是否为空、压栈函数、出栈函数、取栈顶元素、计算栈中有多少个元素、栈有关习题-有效的括号
14 0
|
26天前
|
算法
数据结构和算法学习记录——特殊线性表之栈(上)-栈的概念、栈的结构、链式栈数组栈、栈的结构体定义、栈的基本接口函数、栈顶初始化函数
数据结构和算法学习记录——特殊线性表之栈(上)-栈的概念、栈的结构、链式栈数组栈、栈的结构体定义、栈的基本接口函数、栈顶初始化函数
12 0
|
26天前
|
算法
数据结构和算法学习记录——线性表之双向链表(下)-头插函数、头删函数、查找函数、pos位置之前插入结点、pos位置删除结点及其复用、销毁链表函数
数据结构和算法学习记录——线性表之双向链表(下)-头插函数、头删函数、查找函数、pos位置之前插入结点、pos位置删除结点及其复用、销毁链表函数
12 0