当技术leader说要把接口设计成RESTful,我拒绝了

3,171 阅读4分钟

1、前言

最近准备重写公司一个旧项目,每次想起这个项目,心里总忍不住要吐槽一波,难受。具体细节就不说了,水平不同,见仁见智,也不是本文的重点。就是此时,技术leader说要把接口设计成RESTful规范,我拒绝了,这东西适合当前业务开发吗?前后端对接麻烦吗?

这东西以前上学时就听说过,但工作也没看见有人完全以此设计

我也想遵守这传说中的规范,可现实不允许啊

2、RESTful

REST(Representational State Transfer),直译为表现层资源转换,具体就不说了hhh,相关文章一大堆,但REST感觉没有一个十分明确的标准,更趋向于一种接口设计风格,按照基本的约束条件进行开发设计。

3、基本接口命名

有人说RESTful API可以一下子让别人知道这个url是干什么的,但说到底不就是取决于我们的接口命名吗?接口做到见名知义,用良好的英文命名,不也能达到效果。所以,参考业界部分规范,我定义了如下命名。

3.1 获取数据

拿通用的订单模块举例,最基础无非是两种场景-获取列表 or 获取详情

  1. 获取列表 /api/order/orderList
  2. 获取详情 /api/order/orderInfo

前面不加get?

  1. 之前我也加,时间久了总觉得碍眼hhh,这里定义get,service层又定义一个相同或差不多的方法名,总觉得在重复命名
  2. 为了让接口路径更短更精简,干脆省略get,后面就约定以list/info结尾就认为是获取数据信息了。

不学RESTful在数据实体后加s表示复数?

  1. 对于后端数据结构而言,List更合适
  2. 有些前端需要做列表展示,List翻译后更见名知义
  3. 以s结尾的单词需加es就不说了,有些单词是单复数同行,如果加s我会觉得这人英文语法不行啊,不加又像单数。所以为了统一,List最好

3.2 复杂业务场景

有时我们的核心业务需求不定,相同的实体信息在不同场景需要提供不同的数据,其实到我们后端就是根据不同过滤条件查询出实体信息,有些所谓的RESTful规范说是在url后加参数信息,如:

/orders?state=finish&userId=123

这也是我不喜欢RESTful的原因之一,某些场景下,过滤信息是固定不变的,不能通过前端传参决定,而且url后带参数的传参也有弊端。

回到不同场景不同命名,最好能从产品用户角度出发,比如:

  1. 查看我所有订单/api/order/myAllOrderLIst
  2. 获取已完成的订单/api/order/finishiedOrderLIst
  3. 获取可开票的订单/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里貌似也有提及。