@@ -4,51 +4,32 @@ title: 接口响应
4
4
5
5
我们为 FBA 开发了十分灵活且健全的接口响应系统,它同时适用于任何 FastAPI 应用
6
6
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
-
21
7
## 统一返回模型
22
8
23
9
在常规 web 应用开发中,通常情况下,响应结构总是统一的,但在 FastAPI 的官方教程中,并没有提示我们该如何这样做,其实,这很简单,
24
10
只需我们提供一个统一的 pydantic 模型
25
11
26
12
``` python
27
13
class 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
-
31
14
code: int = CustomResponseCode.HTTP_200 .code
32
15
msg: str = CustomResponseCode.HTTP_200 .msg
33
16
data: Any | None = None
34
17
```
35
18
36
- 以上是我们在 FBA 中的内部实现,由于我们使用的是 pydantic-v2,所以,` json_encoders ` 可能暂时无法按预期工作;
37
-
38
19
以下是使用此模型进行返回的示例(遵循 FastAPI 官方教程),` response_model ` 参数和 ` -> ` 类型我们只需选择其中一种方式即可,因为
39
20
FastAPI 会在内部自动解析并获取最终响应结构
40
21
41
22
` response_model ` 参数
42
23
43
- ``` python{1}
24
+ ``` python{1,3 }
44
25
@router.get('/test', response_model=ResponseModel)
45
26
def test():
46
27
return ResponseModel(data={'test': 'test'})
47
28
```
48
29
49
30
` -> ` 类型
50
31
51
- ``` python{2}
32
+ ``` python{2,3 }
52
33
@router.get('/test')
53
34
def test() -> ResponseModel:
54
35
return ResponseModel(data={'test': 'test'})
@@ -63,31 +44,61 @@ ResponseModel 做为统一响应模型,你会在 Swagger 文档得到(如图
63
44
64
45
显然,我们无法获取响应 Schema 中的 data 结构,前端同事找到你,你会告诉他们,你请求一下不就行了?(没毛病,但显然不太友好),下面就是我们的解决办法
65
46
47
+ ``` python
48
+ class ResponseSchemaModel (ResponseModel , Generic[SchemaT]):
49
+ data: SchemaT
50
+ ```
51
+
52
+ 这是我们创建的用于 Schema 模式的统一返回模型,它的用法与 ` ResponseModel ` 基本相似
53
+
54
+ ` response_model ` 参数
55
+
66
56
``` python{1,3}
67
- @router.get('/test', response_model=ResponseSchemaModel[GetApiListDetails ])
57
+ @router.get('/test', response_model=ResponseSchemaModel[GetApiDetail ])
68
58
def test():
69
- return ResponseSchemaModel[GetApiListDetails ](data=GetApiListDetails (...))
59
+ return ResponseSchemaModel[GetApiDetail ](data=GetApiDetail (...))
70
60
```
71
61
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 文档
74
71
75
72
![ response_schema_model] ( /images/response_schema_model.png )
76
73
77
- 我们可以看到,响应 Schema 中的 data 已经包含我们的响应体结构了,响应体结构正式解析的 ` [] ` 的 Schema 模型,它们是对应的,如果返回的数据结构与
74
+ 我们可以看到,响应 Schema 中的 data 已经包含我们的响应体结构了,响应体结构正是解析的 ` [] ` 中的 Schema 模型,它们是对应的,如果返回的数据结构与
78
75
Schema 不一致,将引发解析错误
79
76
80
- 我们建议将这种方式仅用于查询接口,如果你不需要这种文档/验证,你完全可以不使用它,而是使用更加开放的统一响应模型 ResponseModel
77
+ ==我们建议将这种方式仅用于查询接口==,如果你不需要这种文档/验证,你完全可以不使用它,而是使用更加开放的统一响应模型
78
+ ResponseModel
81
79
82
80
## 统一返回方法
83
81
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() `
85
96
86
97
::: warning
87
98
它们都是同步方法,而不是异步。因为这些返回方法并不涉及 io 操作,所以,定义为异步,不但没有性能提升,反而增加了异步协程的开销
88
99
:::
89
100
90
- ### success()
101
+ ` success() `
91
102
92
103
此方法通常作为默认响应方法使用,默认返回信息如下
93
104
@@ -99,7 +110,7 @@ Schema 不一致,将引发解析错误
99
110
}
100
111
```
101
112
102
- ### fail()
113
+ ` fail() `
103
114
104
115
此方法通常在接口响应信息为失败时使用,默认返回信息如下
105
116
@@ -111,7 +122,7 @@ Schema 不一致,将引发解析错误
111
122
}
112
123
```
113
124
114
- ### fast_success()
125
+ ` fast_success() `
115
126
116
127
此方法通常仅用于接口返回大型 json 时,可为 json 解析性能带来质的提升,默认返回信息如下
117
128
@@ -122,3 +133,37 @@ Schema 不一致,将引发解析错误
122
133
"data" : null
123
134
}
124
135
```
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