当年初生牛犊不怕虎机翻了如何设计RESTful API?,妄图在实践中用起来,在每一个经受的项目中都想实现,每一次都被打脸,时间久了就放弃治疗了。接下来抱怨一些过程中遇到的坑吧。

HTTP 实现 RESTFul API 一共就3件事情,怎么就这么难呢?

  • 看 url 就知道操作什么
  • 看 http method 就知道干什么
  • 看 http status code 就知道结果

难以定义 URL

资源的定义就很难,教程里的案例都是很简单的情况,现实情况复杂得多。
例如,现在有一个需求,一个客户端 A 需要一个用户分页接口,查询条件有姓名、电话、注册时间等。还有一个客户端 B 也需要用户分页接口,但是查询条件有姓名、常用收货地址等。虽然都是分页查询用户,但是实现的逻辑完全不同,一般都是分开定义 API

客户端 A 需要的接口:

GET /v1/users HTTP/1.1
Host: www.demo.com

name=tom&phone=123321&sign_time=2011-01-01

客户端 B 需要的接口:

GET /v1/users/with-common-address HTTP/1.1
Host: www.demo.com

name=tom&phone=123321&common_address=abc%20efg

越是基础数据,越容易遇到多端需要的参数不同,要求返回的数据也不同。特别是遇到实现方法大相径庭的时候,通常都是通过加后缀或者前缀的方式区分。

但是这个例子是可以用一个接口实现的,程序上是可以通过是否包含 commons_address 参数区分不同的处理逻辑。但是这里有个很现实的问题,如果第一个接口已经存在并且工作良好的话,作为接受第二个接口开发的你,有勇气去修改第一个接口的实现吗?特别是在逻辑很复杂,第一个接口的代码可读性不高的时候。

除了以上的问题,当类似的需求过多时,这个接口的参数将越来越多,返回的消息结构包含的字段也越来越多。参数该怎么传,什么情况下哪些参数不能传。返回消息体每个字段什么时候会有值,什么时候没有值。这些都需要在逻辑里实现,并且测试,最后还得同步到 API 文档中。这样的代码难以维护,接口文档难以阅读。

暂时没有找到比加后缀成本更低的方式,或者可以考虑加一个中间层,毕竟 计算机领域的任何问题都可以通过增加一个间接的中间层来解决

被弃用的状态码

应用服务器通常只返回 200、401、500 错误码,其中 401 通常还是由权限框架实现的。更常见的是自定义 code 表示错误原因,如果没有国际化需求的话,大概率这个 code 只有两个值,一个表示成功,一个表示业务逻辑错误。就像下面的例子:

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8

{
    "code": 123321,
    "message": "手机号已经被占用"
}

本质的原因还是大部分业务逻辑上的错误,不需要特殊处理只需要提示就行。所以只需要区分:

  • 成功 http 200, code 0
  • 业务逻辑错误 http 200, code 不等于 0
  • 代码错误 http 500

而且不同 HTTP 状态码,需要编码实现如何处理,但是实现的效果都是把应用服务器返回的消息提示一下而已。这里的坑在于提示信息是硬编码在应用服务器的代码中,如果想改一下提示信息就得发布代码。

POST 一把梭

  • GET 查询
  • POST 新增
  • PUT 修改
  • DELETE 删除

很清晰是不是?但是登录应该用哪个?注销又应该用哪个?获取授权呢?获取签名呢?

参数太复杂客户端说用 POST 他们代码好写一点,项目要延期了改不改?

既然这么多问题搞不清楚还不如 POST 一把梭

永远的V1版本

代码的版本永远都是 1.0.0-SNAPSHOT ,就更别说 URL 的版本了。

如果客户端只有 web,那还升级啥接口的版本哦,直接改就是了。但是客户端中有 APP 呢?直接让旧版本的用户升级就行了,不升级就不然用,这样岂不是很简单。那 URL 还要版本干啥呢? 不如去掉算了。

如果 API 有其他第三方服务在调用呢?那版本号就有用了,但是大多数小厂可没有这种场景,那就只能永远的V1了。

去他喵的接口设计

去他喵的接口设计,时间紧、任务重、变化大,没时间设计,设计好了也得半路改掉,不如直接开撸,写好了导出一个接口文档就行,什么不懂来问啊。

半个月之后,客户端同事问:“这个字段是啥意思啊?”,后端开发:“你稍等啊,我查一查”,内心OS:“我他喵为啥要这个字段呀???好像没啥用,但是又不敢删!哎~~”


等灯的邓
19 声望0 粉丝