许久没有产出了,今天看了掘金上的一篇关于接口设计的文章,因此有感谈谈自己在项目开发中与后的一些想法和反思。
参考:一篇来自前端同学对后端接口的吐槽
以使用者的视角开发接口
对于RESTful风格的前后端分离式开发,接口的设计应该从何种视角出发呢?一般情况下,后端开发人员(我)的想法是:
- 想要实现这个功能,我需要返回哪些数据?
- 我要怎样划分不同的API?
- 当两个接口返回的数据有重复的部分时,我是否需要做一些复用?
- ...
在这种视角下,我开发出的接口虽然实现了项目的需求,但是却可能与其在前端的易用性产生割裂。
一个例子
在我之前独立开发的一个数据可视化系统中,存在着这样一个功能:
该项目的数据存在四种层级:team、group、branch、total,这四个层级的数据项都是一样的,现在需要提供接口分别返回这四个层级的数据。
实际开发中,数据库中存在着四张数据表,而我不想使用MyBatis的${}
以字符串拼接的形式来生成SQL,于是我写了四个逻辑几乎完全相同的Service类,最终反映到Controller上,就是每个层级的数据都有一个API去获取数据。当然,后端这里应该有更好的处理方式,不过暂且按下不表。当我终于大致完成后端的接口设计,转而开发前端时,才发现我接口设计的不合理之处。首先,前端要配置多个axios,其次,发送请求时,前端需要编写多余的代码去选择要调用哪个API,同时,我在后端的swagger2调试页面也臃肿不堪。
现在想起来,这里的“层级”不应作为API划分的依据,而应当作为获取数据这个API的一个参数。在开发过程中,我仅仅是看了一下数据表的划分就匆忙开始了接口的设计与开发,而忽略了它还应当尽可能为使用者服务,这让同时兼任前端开发的我在后来吃到了苦头。实际工作中,开发出这样的接口吃到的可能就是前端开发的砖头了。
数据格式
目前我注意到的接口开发中可能需要额外处理的数据主要有:
时间
Java中后端直接返回的时间格式一般形如:2020-07-29T00:00:00.000+0800;
而前端需要展示的格式一般为:yyyy-MM-dd HH-mm-ss
。
对于返回日期的格式转换我认为放在前端来做比较好,因为前端在不同的地方可能需要对日期进行不同的格式化。如果后端返回格式化好的字符串那前端仍然需要进行一些额外的操作。步骤多一点出bug的几率也会大一点。
对于请求的日期,一般是传字符串,后端进行解析。不知道有没有直接传日期类型的方法呢?每个接口都要解析一次日期字符串还挺麻烦的。顺带一提,swagger中可以通过传Wed, 29 Jul 2020 00:00:00GMT
形式的数据直接识别为Date类型。
百分数
对于“67.2%”这一条数据,前后端的处理方案分别有:
- 前端:0.672、67.2
- 后端:0.672、67.2、"67.2%"
这里的数据格式一般有根据前后端的约定来,感觉没有太大影响。
金额数
由于后端double运算的特性,金额一般使用以分为单位的Integer
类型或bigInteger
计算。同理,前后端交互的金额数据也应使用整型。最近做一个支付接口的测试时发现他们的金额参数确实就是string(以分为单位)。
HTTP状态码
关于HTTP状态码,我一直都有些困惑。一般来说,我们返回的一个response中,会同时包含HTTP status
和自定义的业务code
等信息。例如我在自己项目中封装的统一返回结果:
{
"timestamp": "2020-07-29T00:00:00.000+08:00",
"code": 200,
"message": "success",
"data": 123,
"path": "/result"
}
HTTP状态码代表这次请求的结果,而自定义的code
以及message
代表业务的结果。那么对Forbidden或Unauthorized等情况,我们是否应该同时修改HTTP status
和code
呢?如果是的话,那么这两个标识看上去就有了冗余,没有很好地做到“各司其职”,虽然这并不影响整个系统的运行,但是我总在想这方面会不会有更合适的实现方式。