当年初生牛犊不怕虎机翻了如何设计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:“我他喵为啥要这个字段呀???好像没啥用,但是又不敢删!哎~~”
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。