1、前言
最近准备重写公司一个旧项目,每次想起这个项目,心里总忍不住要吐槽一波,难受。具体细节就不说了,水平不同,见仁见智,也不是本文的重点。就是此时,技术leader说要把接口设计成RESTful规范,我拒绝了
,这东西适合当前业务开发吗?前后端对接麻烦吗?
这东西以前上学时就听说过,但工作也没看见有人完全以此设计
我也想遵守这传说中的规范,可现实不允许啊
2、RESTful
REST(Representational State Transfer),直译为表现层资源转换,具体就不说了hhh,相关文章一大堆,但REST感觉没有一个十分明确的标准,更趋向于一种接口设计风格
,按照基本的约束条件进行开发设计。
3、基本接口命名
有人说RESTful API可以一下子让别人知道这个url是干什么的,但说到底不就是取决于我们的接口命名吗?接口做到见名知义
,用良好的英文命名,不也能达到效果。所以,参考业界部分规范,我定义了如下命名。
3.1 获取数据
拿通用的订单模块举例,最基础无非是两种场景-获取列表
or 获取详情
- 获取列表
/api/order/orderList
- 获取详情
/api/order/orderInfo
前面不加get?
- 之前我也加,时间久了总觉得碍眼hhh,这里定义get,service层又定义一个相同或差不多的方法名,总觉得在
重复命名
。- 为了让接口路径更短更精简,干脆省略get,后面就约定以
list/info结尾
就认为是获取数据信息了。
不学RESTful在数据实体后加s表示复数?
- 对于后端
数据结构
而言,List更合适- 有些前端需要做列表展示,List翻译后更
见名知义
- 以s结尾的单词需加es就不说了,有些单词是单复数同行,如果加s我会觉得这人英文语法不行啊,不加又像单数。所以为了统一,List最好
3.2 复杂业务场景
有时我们的核心业务需求不定,相同的实体信息在不同场景需要提供不同的数据,其实到我们后端就是根据不同过滤条件查询出实体信息,有些所谓的RESTful规范说是在url后加参数信息,如:
/orders?state=finish&userId=123
这也是我不喜欢RESTful的原因之一,某些场景下,过滤信息是固定不变的,不能通过前端传参决定
,而且url后带参数的传参也有弊端。
回到不同场景不同命名,最好能从产品用户角度
出发,比如:
- 查看我所有订单
/api/order/myAllOrderLIst
- 获取已完成的订单
/api/order/finishiedOrderLIst
- 获取可开票的订单
/api/order/invoiceOrderList
3.3 增/改/删/其他非获取动作
- addXXX - 增加
- saveXXX -保存
- updateXXX -修改更新
- deleteXXX -删除
- pushXXX -推送
- payXXX -支付
- ........
如果做后台管理系统这种项目,确实可以用list、info、save、update、delete一把梭了。每个数据实体必定要有这些方法
3.4 myBatis-plus中良好的命名
myBatis-plus封装好了一些service、mapper方法,增删改查都有十分规范的命名。而且在相同的操作都有适合自己的命名。
动作 | service | mapper(dao) |
---|---|---|
增 | save | insert |
删 | remove | delete |
改 | update | update |
查 | get/list | select |
3.5 不同版本的相同接口
有些接口需要兼容不同的APP版本,如果增加字段不能满足,迫不得已需增加新的请求路径,可加个v1、v2版本前缀
,原接口名不变,加个版本前缀还可以看到接口的历史修改,方便维护。
/api/order/v1/orderInfo
/api/order/v2/orderInfo
4、统一ApiRequest
4.1 Spring还天然支持RESTful规范
除了场景的GET、POST请求注解,Spring还有@PutMapping 、@PatchMapping、 @DeleteMapping 注解,标识不同的请求方式。
不仅如此,SpringMVC还支持参数绑定。
@RequestMapping(value = "/orders/{id}", method = RequestMethod.GET)
public void getById(HttpServletRequest request, @PathVariable("id") Long id){
System.out.println(id);
}
这....又给我们提供一种获取参数的形式..............
4.2 自定义ApiRequest
既然拒绝了RESTful,那我们规定,前端统一用json形式POST请求接口传递参数,后端拦截器拿到请求,自定义ApiRequst类,将请求信息(请求头/请求体)统一封装,这样前后端架构都保持统一,更有利于联调。
@Data
public class ApiRequest implements Serializable {
private String appVersion; //请求头-app版本号
private Integer deviceType; //请求头-设备类型
private String deviceName; //请求头-设备类型
private String secret;
private String token;
private Map data; //请求体-业务参数
}
Controller层统一形式接收
/**
* TestApi
* @param apiRequest
* @return
*/
@PostMapping(value = "/testList")
public ApiResponse testList(ApiRequest apiRequest) {
Long id = apiRequest.getDataParamAsLong("id", 0L);
String name = apiRequest.getDataParamAsString("name", "");
return ApiReponse.ok();
}
5、写在最后
其实我不并反对RESTful
,仅仅想说出自己的想法。存在即合理嘛。我也曾经尝试过其规范,真是一把辛酸泪。我觉得只有适合自己的业务,能提高开发效率、前后端沟通效率的,就是良好的规范,规范并没有一个十分统一的参考
。
咦,好像还漏了接口返回结果Response没说吧,这在RESTful里貌似也有提及。