@@ -4,51 +4,32 @@ title: 接口响应
44
55我们为 FBA 开发了十分灵活且健全的接口响应系统,它同时适用于任何 FastAPI 应用
66
7- ## 响应状态码
8-
9- 在文件 ` backend/common/response/response_code.py ` 中内置了多种定义响应状态码的方式,我们可以根据 ` CustomResponseCode ` 和
10- ` CustomResponse ` 定义自己需要的的响应状态码,因为在实际项目中,响应状态码并没有统一的标准
11-
12- 当我们定义好自定义响应状态码之后,可以向下方这样使用
13-
14- ``` python{3-4}
15- @router.get('/test')
16- def test() -> ResponseModel:
17- res = CustomResponse(code=0, msg='成功')
18- return ResponseModel(res=res, data={'test': 'test'})
19- ```
20-
217## 统一返回模型
228
239在常规 web 应用开发中,通常情况下,响应结构总是统一的,但在 FastAPI 的官方教程中,并没有提示我们该如何这样做,其实,这很简单,
2410只需我们提供一个统一的 pydantic 模型
2511
2612``` python
2713class ResponseModel (BaseModel ):
28- # TODO : json_encoders 配置失效: https://github.com/tiangolo/fastapi/discussions/10252
29- model_config = ConfigDict(json_encoders = {datetime: lambda x : x.strftime(settings.DATETIME_FORMAT )})
30-
3114 code: int = CustomResponseCode.HTTP_200 .code
3215 msg: str = CustomResponseCode.HTTP_200 .msg
3316 data: Any | None = None
3417```
3518
36- 以上是我们在 FBA 中的内部实现,由于我们使用的是 pydantic-v2,所以,` json_encoders ` 可能暂时无法按预期工作;
37-
3819以下是使用此模型进行返回的示例(遵循 FastAPI 官方教程),` response_model ` 参数和 ` -> ` 类型我们只需选择其中一种方式即可,因为
3920FastAPI 会在内部自动解析并获取最终响应结构
4021
4122` response_model ` 参数
4223
43- ``` python{1}
24+ ``` python{1,3 }
4425@router.get('/test', response_model=ResponseModel)
4526def test():
4627 return ResponseModel(data={'test': 'test'})
4728```
4829
4930` -> ` 类型
5031
51- ``` python{2}
32+ ``` python{2,3 }
5233@router.get('/test')
5334def test() -> ResponseModel:
5435 return ResponseModel(data={'test': 'test'})
@@ -63,31 +44,61 @@ ResponseModel 做为统一响应模型,你会在 Swagger 文档得到(如图
6344
6445显然,我们无法获取响应 Schema 中的 data 结构,前端同事找到你,你会告诉他们,你请求一下不就行了?(没毛病,但显然不太友好),下面就是我们的解决办法
6546
47+ ``` python
48+ class ResponseSchemaModel (ResponseModel , Generic[SchemaT]):
49+ data: SchemaT
50+ ```
51+
52+ 这是我们创建的用于 Schema 模式的统一返回模型,它的用法与 ` ResponseModel ` 基本相似
53+
54+ ` response_model ` 参数
55+
6656``` python{1,3}
67- @router.get('/test', response_model=ResponseSchemaModel[GetApiListDetails ])
57+ @router.get('/test', response_model=ResponseSchemaModel[GetApiDetail ])
6858def test():
69- return ResponseSchemaModel[GetApiListDetails ](data=GetApiListDetails (...))
59+ return ResponseSchemaModel[GetApiDetail ](data=GetApiDetail (...))
7060```
7161
72- 我们可以看到,这里其实和统一响应模型 ResponseModel 差不多,关键就在于我们这里多了一个 ` [xxxSchema] ` ,没错,这就是关键,此时我们再来看一眼
73- Swagger 文档
62+ ` -> ` 类型
63+
64+ ``` python{2,3}
65+ @router.get('/test')
66+ def test() -> ResponseSchemaModel[GetApiDetail]:
67+ return ResponseSchemaModel[GetApiDetail](data=GetApiDetail(...))
68+ ```
69+
70+ 此时我们再来看一眼 Swagger 文档
7471
7572![ response_schema_model] ( /images/response_schema_model.png )
7673
77- 我们可以看到,响应 Schema 中的 data 已经包含我们的响应体结构了,响应体结构正式解析的 ` [] ` 的 Schema 模型,它们是对应的,如果返回的数据结构与
74+ 我们可以看到,响应 Schema 中的 data 已经包含我们的响应体结构了,响应体结构正是解析的 ` [] ` 中的 Schema 模型,它们是对应的,如果返回的数据结构与
7875Schema 不一致,将引发解析错误
7976
80- 我们建议将这种方式仅用于查询接口,如果你不需要这种文档/验证,你完全可以不使用它,而是使用更加开放的统一响应模型 ResponseModel
77+ ==我们建议将这种方式仅用于查询接口==,如果你不需要这种文档/验证,你完全可以不使用它,而是使用更加开放的统一响应模型
78+ ResponseModel
8179
8280## 统一返回方法
8381
84- ` response_base ` 是我们做的全局基础响应实例,此实例包含三个开放式方法,分别为:` success() ` 、` fail() ` 、` fast_seccess() `
82+ ` response_base ` 是我们做的全局响应实例,它大大简化了响应返回方式,用法如下:
83+
84+ ``` python{3,8}
85+ @router.get('/test')
86+ def test() -> ResponseModel:
87+ return response_base.success(data={'test': 'test'})
88+
89+
90+ @router.get('/test')
91+ def test() -> ResponseSchemaModel[GetApiDetail]:
92+ return response_base.success(data=GetApiDetail(...))
93+ ```
94+
95+ 此实例包含三个返回方法:` success() ` 、` fail() ` 、` fast_sucess() `
8596
8697::: warning
8798它们都是同步方法,而不是异步。因为这些返回方法并不涉及 io 操作,所以,定义为异步,不但没有性能提升,反而增加了异步协程的开销
8899:::
89100
90- ### success()
101+ ` success() `
91102
92103此方法通常作为默认响应方法使用,默认返回信息如下
93104
@@ -99,7 +110,7 @@ Schema 不一致,将引发解析错误
99110}
100111```
101112
102- ### fail()
113+ ` fail() `
103114
104115此方法通常在接口响应信息为失败时使用,默认返回信息如下
105116
@@ -111,7 +122,7 @@ Schema 不一致,将引发解析错误
111122}
112123```
113124
114- ### fast_success()
125+ ` fast_success() `
115126
116127此方法通常仅用于接口返回大型 json 时,可为 json 解析性能带来质的提升,默认返回信息如下
117128
@@ -122,3 +133,37 @@ Schema 不一致,将引发解析错误
122133 "data" : null
123134}
124135```
136+
137+ ## 响应状态码
138+
139+ 在文件 ` backend/common/response/response_code.py ` 中内置了多种定义响应状态码的方式,我们可以根据 ` CustomResponseCode ` 和
140+ ` CustomResponse ` 定义自己需要的的响应状态码,因为在实际项目中,响应状态码并没有统一的标准
141+
142+ 当我们定义好自定义响应状态码之后,可以像下面这样使用
143+
144+ ``` python{3-4}
145+ @router.get('/test')
146+ def test() -> ResponseModel:
147+ res = CustomResponse(code=0, msg='成功')
148+ return ResponseModel(res=res, data={'test': 'test'})
149+ ```
150+
151+ ## 驼峰返回
152+
153+ 我们默认使用 python 下划线命名法进行数据返回,但是,在实际工作中,前端目前大多使用小驼峰命名法,所以,我们就需要对此进行一些修改来适配前端工程,在文件
154+ ` backend/common/schema.py ` 中,我们有一个 ` SchemaBase ` 类,它是我们的全局 Schema 基础类,修改如下:
155+
156+ ``` python
157+ class SchemaBase (BaseModel ):
158+ model_config = ConfigDict(
159+ populate_by_name = True , # [!code ++] 允许通过原始字段名或别名进行赋值
160+ alias_generator = to_camel, # [!code ++] 自动将字段名转换为小驼峰
161+ use_enum_values = True ,
162+ json_encoders = {datetime: lambda x : x.strftime(settings.DATETIME_FORMAT )},
163+ )
164+ ```
165+
166+ 其中,` to_camel ` 方法引入自
167+ pydantic,详情:[ pydantic.alias_generators] ( https://docs.pydantic.dev/latest/api/config/#pydantic.alias_generators )
168+
169+ 完成以上修改后,Schema 模式和返回数据将自动转为小驼峰命名
0 commit comments