浅谈 Api 设计

之前在团队内做了一次 Api 的规范化,决定采用 RESTful Api 的架构。 并统一了 JSON 结构,约定常用属性、字段的命名方式、URL/HTTP Method 的使用规则。
这样的好处不用多说,一个方便易懂,易于使用的 Api 能大大的提高开发效率(做开发的有谁没被第三方 Api 坑过?)

设计过程

之前我们有一些设计比较不错的 api 可能是这样的:

/user/(add/get/cancel)?id=123
/topic/(create/destroy/destroy_batch)?id=123 

也算是简单易懂了,那为什么要换成 RESTful 架构?(关于 REST 的特性,设计思想什么的就不说了,网上自取)这样带来最直接的问题就是不统一(规范)。我的 CRUD 叫 add/get/cancel,换一个人可能叫 create/modify/destroy, 甚至可能我的是 adduser 你的是 useradd (瞬间想到了 ubuntu 有木有!)。

规范这东西小范围没什么大问题, 一但队伍庞大了就是个大坑,所以大公司在规范上都是下了大功夫。

HTTP 协议就是一个标准的 REST 实现,RESTful Api 是以 HTTP 协议为强烈依托的,最终我们规范后是这样的:

/user/{uid} HTTP.GET/POST/PUT/DELETE
/topic/{tid} HTTP.GET/POST/PUT/DELETE

暂时只使用这四个方法,使用 PUT 替换 PATCH。很多人对部分情景下 PUT / POST 的使用会有疑问:

解答:根据 HTTP 文档介绍,GET/HEAD/PUT/DELETE 是 Idempotent(重复执行多遍,結果一致)。  
POST 每次执行肯定会新增一条记录,大多数情况下可以根据此原则从 POST/PUT 中选择合适的动作。  

/模块/{id} HTTP.Mehod 这种统一的规范能节省出不少的沟通时间~ 刚开始感觉很美好,当场景多起来之后又出现一些新的问题:
有一种功能叫「撤单」,使用 /order/{oid} HTTP.DELETE吗? 那删除订单用什么呢?
所以有人开始用 /order/undo/{order_id} HTTP.PUT 类似的方式。按 REST 规范每个 URL 都是一个独立资源,其中不应该包含任何动作。
也许应该改成 /order/{oid}?action=undo HTTP.PUT,但这样可能会在同一个接口中引入过多的操作。

类似这样的模糊的场景可能有许多,在 Api 数量随业务庞大的过程中需要反复的对当前 Api 做迭代重构,使它更适合当前的业务场景

那满足以上设计就是 RESTful Api 吗?
eg: /topic/fav/{tid} HTTP.POST 收藏某个话题

这个接口需要从 token 中获取登陆用户信息,且所有的用户都是访问同一个地址。
这与 REST 架构中的「无状态」和「唯一资源」的概念冲突。
按要求可能是这样的:

/topic/{uid}/fav/{tid} 

当然这些都是 REST 的建议,如何做还是要根据具体的业务情况而定

总结下来就是以下几点:
  1. 规范很重要
  2. 保持 Api 的优雅是一件持续的重复迭代的工作
  3. 不要局限于各种规范中,要在设计规范的时候充分考虑业务上的灵活性