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


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

JSONResponse:

response_model:

背景
@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

问题来了

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

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

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

发起请求,查看响应

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

根本原因

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

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

return user 断点

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

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

  • 如果是合作开发,还是有必要的,因为 response_model 可以自动添加 JSON Schema、Example Value 在 Swagger 文档中,可读性大大提升
  • 但它的作用也仅是提供 JSON Schema、Example Value

 

  • 本文作者: 小菠萝测试笔记
  • 本文链接:
  •