API Story

主要是整理 Restful api设计时候的一些体会以及别人的实践经验。

restful api 设计 Tips

涉及到多个组件协作的时候,对外暴露api的这种,api抽象的这种问题更多的是一个经验问题,不是像一个算法那样,有着明确的流程或者对错。而一般对于经验性的问题,往往都没有特别明确的对错的限制,这一类的问题都有一些所谓的规范和原则在里面的,就比如对于代码格式规范,比如golang的规范,golang code review,比如google的代码格式规范。偶尔看到了微信公众号”嘀嗒嘀嗒”中一篇文章,把结合自己的体会整理一下。

返回状态码

返回码的话,是很再常见不过的了,但是实际上使用的时候,常常太过随意,不够规范,这一点子自己要调整过来,比如这个文章(https://www.cnblogs.com/liulei/archive/2010/05/25/1743315.html)就整理的很好,关于返回码的具体含义。总之,按照规范进行设计是一个既简单又不简单的事情。

同时考虑上下游

考虑上游的话,就是输入信息的检查,不要对上游的输入信息的正确性做任何假设,上游可能输出一些奇怪的字符,或者很长的字符,导致程序发生未知错误。

考虑下游的话,就是返回码的正确性检验,一定要按照规定的方式返回对应的返回码,这样下游的调用方再调用api的时候才能有更明确的状态,不要随便修改返回字段的格式,特别是线上的项目,因为不知道下游是怎么处理的,所以返回的字段一旦发生了改变,下游的处理上可能会出现未知的错误。

说白了就是做到瞻前顾后,上下游都要考虑到。

遵循资源名称

restful的核心理念是 every thing is a resource,在设计api的时候,尽量把每个字段都设计成资源名称的形式。所有的action接口,都应该是resource上的CRUID操作,如果脱离这种模式,就需要考虑一下,这样的api设计是否为必要的。

不光是api设计的时候要按照资源的层级构建,类似的思路还可以用在定义label的方式上面,比如docker中,在定义和生成label的时候,可以参考官方文档中所推荐的方式,就是按照namespace的范围来定义的。

不同层次的资源类型也可以通过label来识别,比如docker engine层面的label,容器层面的label。对于k8s来说,pod,service,rc几个层次的资源之间都是通过label来进行group和资源控制的。

认证和授权

这部分自己也没有太多的经验,可以参考之前kube-apiserver的实现,理想情况是尽量安全,但是尽量安全的话,也意味着授权部分的代码实现复杂程度很高,常用的是username+password的方式,还有一种情况是在header中添加bare token进行认证。

关于幂等性

幂等性的根本问题在于对并发问题的处理上,好多时候,对外暴露的api都需要满足幂等性(似乎只是一个本身被默认的性质了)。当然这是一个数学概念,从数学的角度上,不做过多的深入理解,从程序本身的角度上来看,就是一次调用一个http请求,和多次调用一个http请求,所产生的行为应该是一致的。

1
每次对外暴露一个新的api之后,一定要考虑一下这个api自身的幂等性,做一下假设,梳理一下整条逻辑,并发处理的时候,或者多次处理的时候,是否还符合幂等性

最近就遇到了一个幂等性没有被处理好的http请求的例子。 一般一个http请求,如果整个过程中涉及到的环节比较多的话,或者时间比较长的话,在实际进行操作的时候,就容易违反幂等性的设计原则(总是先验地任务请求是一个一个过来的,即一个请求被处理完之后再过来一个请求,实际上并非是这样的)。

一般遇到幂等性的问题,可以从api的耦合度上进行考虑,看是否需要对api进行更细粒度的拆分,还是有就是程序上的原因,是否在一个api的proccess还在处理的过程中,另一个api请求已经过来,在这个过程中,是否会发生异常。也就是在并发处理上,是否有把各种情况都考虑的周到。比如一个完整的流程中会有1,2,3,4多个小的步骤,第一个请求在执行到某个步骤的时候,第二个请求又进来,这样会不会有冲突,是第一个请求又重新被执行呢,还是说由于上一次操作没有被执行完,就直接抛弃这个请求,就是说原子性的粒度要被控制在哪个范围。

从这个角度上来看,对外暴露api,特别是暴露那些会引起系统内部状态发生改变的api,是一件十分严谨又十分有技术含量的事情,因为你需要把用户的各种行为都要考虑到,分类处理要全面,考虑到不同行为对系统造成的影响是否符合业务本身的逻辑定义,而实际上用户的行为往往是很难被全面预料到的。

其他

尽可能的保持api的幂等性,说白了就是同一个request发一次和发两次的时候,结果是不是相同的,request失败的时候,重发第一次是不是还能保持相同的结果,具体实现还是要结合具体的使用场景来看。

还有一些tips,比如”考虑未来的使用场景,设计时留有余地,永远只需要实现production确实要使用到的功能”

参考资源

主要是参考微信公众号”嘀嗒嘀嗒”中的一篇名为”API杂谈”的文章

推荐文章