北漂IT民工 的博客

一次良好的API设计的尝试:蛋蛋API

RESTful APIs存在的问题

基于上次我们对良好API的设计的讨论,我们发现RESTful APIs存在一些问题:

  1. 以描述资源为主,而API的设计并非只是描述资源的
  2. 接口是无状态的,而实际的业务都是有状态的。HTTP协议最终通过引入cookies或者session来维持状态,也引入了更多的安全问题。,所以无状态,会增加接口的不安全性。
  3. 只支持HTTP协议,无法支持Websocket协议或者其它的协议。
  4. 将协议与应用混合起来, 同时协议动作数量又有限。可以感受明显的耦合与冲突,与良好的API设计是相悖的。
  5. 过于学术化,不够亲民
  6. 无法简单的描述清楚
  7. 同时将所有的接口当成资源不符合实际的互联网业务实际。

实用的,良好的,明确的,面向业务的,新的API规范的需求

所以基于这个问题,我们需要设计一个更加实用的API。

  1. 将RESTful APIs独立出来成为专门的文件资源的表达
  2. 将所有业务资源API独立出来,通过一个专门的API规范来定义,我们将这个规范定义成蛋蛋API(egg api)

蛋蛋API

基于上面的讨论,我们认为将文件资源与业务资源分离会是一个更好的选择。
文件资源可以直接基于文件服务器或者基于RESTful APIs的接口,而业务资源通过蛋蛋API来描述。
所以我们要明确蛋蛋API要解决的问题。

面向业务资源

由于蛋蛋API解决的是业务资源的操作与获取,所以需要像RESTful APIs具备很强的自描述性的,从而也不需要基于MIME的文件类型描述。所以我们的返回文件格式只有一种:JSON。
通过JSON可以很好的表达业务资源的数据与业务的操作。
也就是我们不再是Represtative了,而是DATA ONLY。
也就是不再关注如何表达,表示,只关注数据与业务的传递。

错误处理

在RESTful API里错误是基于HTTP Code的方式来表达的。
但是HTTP Code的方式有两个缺点:

  1. code数量有限
  2. 错误面向的是协议,与业务的关系性较弱

所以蛋蛋API规定了基于的错误与返回数据格式

API风格与规范

在蛋蛋API中吸收RESTful APIs资源定位的理念,初步建立以下一些基本规范:

  1. 将业务资源通过URI进行定位
  2. 通过类HTTP方法实行对资源的操作
  3. GET方法用于获取业务资源数据,不影响数据变化
  4. POST方法用于操作数据,可能会导致数据生成,变更,消失。
  5. API可不限于HTTP协议,也可以适合于可能的HTTP的变种协议
  6. 明确所有的操作以名词开始。在URI中,不包含可发生资源变更的动词
  7. 所有变更通过POST提交,并将变更的动词放在action参数下面。

URI的query参数规范

在蛋蛋API里完全将Query当成是查询,但是除去了ID查询。
因为通过URI就可以定位ID查询的结果。

在URI中第一个?号后的参数称为query参数,一般的形式是name=value&name1=value1这样的。
在这里,我们基于HTTP的query,实现对数据的查询。

分页

参数名page表示页码,limit表示每页数据量。

所以获取第5页,每页50个数据的query是这样的:

1
uri?page=5&limit=50

默认值: page=1, limit=20。

会话

如果蛋蛋API的会话是基于token的。token将会被放在query里。

代码示例:

1
uri?token=xxx

状态查询

每个业务资源都是可以有状态的,所以我们提供了state来表示状态。
建议所有的状态都使用state来表达。同时状态值使用大写字符串来表达。

代码示例:

1
uri?state=GOOD

时间段匹配

在query里面提供了时间查询字串:from, to。
可以单独使用,也可以混合使用。查询格式是 YYYY-MM-DD HH:MM:SS。
可以不断减少精确度,直到只有年。
所以可以是
YYYY-MM-DD HH:MM, YYYY-MM-DD HH, YYYY-MM-DD, YYYY-MM, YYYY
这几种格式。
月日不足10时需要使用0补足。
小时采用24小时制。

代码示例:

1
uri?from=1998-09-01&to=2000-01-20 20:10

URI的POST参数规范

由于蛋蛋API采用POST来改变数据,所以我们对POST数据作出如下规范

  1. 提交的数据要与HTTP的表单提交一致
  2. 以action字段取代RESTful APIs里面的HTTP方法
  3. 所以业务变更必须通过类HTTP的表单提交。
  4. 不能将业务逻辑写在文件里,通过文件提交。比如将业务逻辑写到JSON文件里提交到服务器。
  5. 所有的变更参数必须通过POST提交。

一个POST示例:

1
2
3
4
5

POST /users


action=register&name=aaa&password=asdfsf

总结

至此我们已经将蛋蛋API与RESTful APIs的一些特点与优缺点描述完整。
我们在文件资源表示时,可以采用RESTful,而在业务表示时,使用蛋蛋API的规范会让你更加的得心应手。所以对于不同的情况采用不同的策略也许是一个更加可行的办法,不拘泥于RESTful APIs还是蛋蛋APIs。也许,你可以发展出来一套更加有效的API。

蛋蛋API的出发点是实现一套更加实用的,不受HTTP约束,更加面向业务的API规范,所以方向与RESTful APIs是不同的。蛋蛋API面向的更多的是业务资源,而REST将所有的内容都当成是资源表达,并不是我们所同意的看法,所以我们有意将蛋蛋API定位于面向业务资源而不是文件资源,从而可以让我们的API变的更加简单,从而不需要Representive,也不需要MIME。

我们遵从常识大于配置的观念,希望通过固化一些共同的属性,达到最大的一致化API。

目前蛋蛋API仍处于早期阶段,仍有很多可以改进与可以规范的地方。
所以非常欢迎对于优化API,改进规范,促成更好的API协作感兴趣的同仁一起参与改进。

egg api规范地址:

https://github.com/calidion/egg