最近开发若干工程,有一些问题困惑不解,如何成为一个更好的Coder,如何让接入方在使用过程中的学习成本更小?如何让设计的系统更加符合行业规范?如何体现出一个工程的高质量?
写下这篇文章用于鞭策自己在API设计方向上的思考,会不断更新。该文章仅仅设计HTTP(S)下的API设计,对于内部应用,还是推荐使用RPC进行microservice之间的沟通,虽然目前我们还没有。
先说一下我的几个观点:
API的设计就是后端程序员的UI,你必须仔细考虑它的用户体验
我们不应该去追求正宗的RESTful风格,而是愿意使用其思想来处理修饰一些URI
完全正宗的RESTful固然存在并且被使用了,特别适用于特大项目的开放平台API,对于内部的应用,要不要花大量地时间去遵守各种细节,应该由各个团队自己去权衡
RESTful是什么?
REST=representationnal state transfer。表述型状态转移。它不是一种标准,而是一种接口设计风格。
RESTful API指的是按照REST风格来设计的API,它主要有几个特点:
1.网络上所有的事物都抽象为资源,资源有唯一的标识符
2.同一个资源有不同的表现形式(JSON/XML/...)
3.所有的操作都是无状态的(API服务器可水平扩展)
所以,REST是一种面向资源的架构设计风格,面向资源是最重要的特点。关注“资源”究其本质是关注“数据模型”,能够帮助不同组件更好地解耦,消除依赖关系,以及增大系统扩展性。
相反地,SOAP的特点是关注行为和处理,与REST有着很大的不同。
标准的使用姿势
如何去测试你的API是否是一个真正的RESTful API?
黄金标准:API=协议+域名+版本+路径+HTTP动词+过滤信息+状态码+错误处理+返回结果
举个例子:
栗子:GET https://api.douban.com/v2/note/user_created/:id?withAll=true
-------动词--协议----------------域名-----------版本------路径----------------------过滤信息----------------
打假过程&&最佳实践
1.请求方法支持GET/POST/UPDATE/DELETE
2.请求响应严格遵守HTTP状态码:
3.返回结果使用JSON
4.API中有版本的概念
5.使用token做身份认证
6.urI中不出现大写字母
7.urI中使用_连接不同的单词
8.有一份漂亮的文档(尤其重要)
9.非内网应用使用HTTPS
适用于什么场景?
RESTful特别适用于开放平台的API开发。对于未知的调用者,你要尽可能地遵守业界的规范,返回尽可能多的信息。
相反地,对于公司内部的微服务应用,比如电商平台的前后端开发,如果单纯为了REST而ful并不可取。
很可能,某个渠道的前端的兄弟们已经习惯了把200当做唯一正常的状态码来访问。如果渠道的兄弟们人数众多,为了和谐,还是建议多多沟通然后在新系统上使用RESTful风格设计。
对于已发布的非REST风格,不建议修改为REST。因为一旦发布,对外的API将很难改变。
存在即合理&&为什么会有RESTful?
没有RESTful之前,我们是这样调用API的-------有了RESTful之后,我们是这样调用API的
/api/v1/user/query?uid=1 GET ------- /api/v1/user/1 GET
/api/v1/user/delete?uid=1 GET ------- /api/v1/user/1 DELETE
/api/v1/user/update?uid=1 POST ------- /api/v1/user/1 PUT
/api/v1/user/save POST ------- /api/v1/user POST
前者我们在请求URI中定位资源与动作。后者在URI中定位资源、在HTTP METHOD中定位动作。
网络上大部分的REST相关的博客涉及的内容都是URI的设计或REST的使用规范,但我觉得REST的核心在于,当你设计一个系统的时候,资源是第一位的考虑,你要从资源的角度来进行系统的拆分、设计;而不是像以前一样以操作为角度来进行设计。达成这样的目的:1.容易写出规范化URI,2.规范化使用了HTTP协议,不再只有200和500。
我们平时是这样设计系统的:有下单功能->下单需要一个URL→往这个URL发送的数据要定义好→开始写前端和后端。我们先确认一个操作,然后围绕这个操作去做业务实现。这样虽然可以设计出好的系统,但是可能会有这样的问题:1.操作之间的关联导致业务的复杂,比如“下单”操作要依赖于“查票”操作之前。2.系统的URI设计缺乏一致性。3.很少规范化使用HTTP状态码。
深挖下来,我们是把HTTP当做一个传输的通道,还是一个传输的协议?如果只是传输的通道,那么HTTP的状态码应该只有200和500,200代表这条路可以走,500代表走不了。
如果当做传输的协议,那HTTP本身的状态码其实就规范了很多操作。
大神语录:
REST的目的是“建立十年内不会过时的软件系统架构",所以它具备三个特点:
1. 状态无关 —— 确保系统的横向拓展能力
2. 超文本驱动,Fielding的原话是”hypertext-driven" —— 确保系统的演化能力
3. 对 resource 相关的模型建立统一的原语,例如:uri、http的method定义等 —— 确保系统能够接纳多样而又标准的客户端
从另外一个角度看,第一条保证服务端演化,第三条保证客户端演化,第二条保证应用本身的演化,这实在是一个极具抽象能力的方案。
文章最后的但是:
1.复杂的关系,操作,资源集合,硬性套用REST原则设计非常困难
有的动作无法抽象成资源,例如登录。但是我们可以把登录转换成【申请/发放令牌】这几个动作。
2.状态码完全不够用:比如,登录错误:
是因为频率限制、账号密码错误、用户不存在...等等原因,最终我们还是要有自己的BizErrorCode。
3.对于不能抽象成资源的:https://api.douban.com/v2/book/search?q=python&fields=id,title
4.多人纠结get(查询)/post(增加)/delete(删除)/put(修改),连Roy Thomas Fielding都这么说,我认为这完全是个误区,因为把软件的业务场景过于简单化了。
难道我们的系统就只实现这四类操作么,那么我问你,发短信、支付、用户登录认证,这算是哪一个?