Web API 概论 - 引言

Web API 的定义

Web API 的简单定义:一种通过网络,依照预先定义好的规则进行通信的方式。这里网络可以是本地网络,局域网络,或者广域网络。网络的类型会影响API的风格,但是不影响其功能。

在Web API 里,我们还需要定义如下角色:

  • Server:一个程序,这个程序定义了一套API,并且提供了API 的一个实现以及调用机制。
  • Client:一个程序,这个程序使用了Server 定义的API 来服务自己的业务,在某些情况下也可能实现Server 定义的API(Callback)。

这里有两点需要注意,Server 同时负责API 的定义和实现。程序间的依赖关系是Client 单向依赖于Server。

Web API 的非正交分类

考虑如下API 的风格要素,不同要素的组合最终会形成不同的API 类型:

  1. 通讯方式 PULL/PUSH
  2. 通讯信道 ONE-WAY/BI-DIRECTIONAL
  3. 通讯协议 TCP/HTTP
  4. 负载类型 TEXT/BINARY
  5. 生命周期 STATEFUL/STATELESS
  6. 作用范式 COMMAND/DECLARITIVE

通讯方式 PULL/PUSH

PULL - 拉式通信,由Client 向Server 发起通讯并且处理获得结果。PULL 是最常见的API 工作方式,并且通常都会期待一个API 结果,因为Client 对于Server有信息上的请求来满足其自己的业务需要。返回空(EMPTY)也是结果的一种,代表请求已经被知晓。

PUSH - 推式通信,由Server 向Client 发起通讯,对于结果有选择性的处理。因为Client -> Server 的单向依赖关系,Server 并不知晓,也不应知晓Client 的业务,所以这里Server 仅仅处理其通讯部分的结果,甚至在某些情况下连通讯结果都不予理会。

通讯信道 ONE-WAY/BI-DIRECTIONAL

这里的通信信道指的是由谁发起通讯。

ONE-WAY - 仅有一方发起,比如仅支持PULL 或者PUSH。单向通讯通常有着更好的网络拓扑兼容性。

BI-DIRECTIONAL - 双方都可以发起通讯,也就是同时支持PULL 和PUSH。虽然PUSH 通讯可以由Client 发起的长链接来维持,或者借由第三方组件中转来避规对于Client 网络可见性的需求,但是大多数情况下Client 的网络可见性可以极大简化通讯架构。

通讯协议 TCP/HTTP

Web API 都是应用层协议,它可以选择假设在传输层协议(比如TCP)或者应用层协议(比如HTTP)上。

TCP - 选择TCP 一般都是为了传输效率,省掉了额外的应用层开销。

HTTP - 选择HTTP 则是为了方便,HTTP 已经被广泛应用,开发调试生态环境优秀。

负载类型 TEXT/BINARY

负载类型本质上是负载的序列化与反序列化,在选择的时候通常考虑以下因素:表达能力,兼容性,序列化、反序列化效率,最终数据大小,是否开发、Debug友好等。

TEXT - 目前广受欢迎的类型,包含了JSON,XML等一些列格式。TEXT 最大的好处在于表达能力,兼容性,开发、Debug 友好。任何编辑器都可以毫无压力的编辑各种文本类型文件。并且由于网络带宽的提升以及泛压缩能力的应用,其数据大小通常也不再是一个问题。

BINARY - 一些远古RPC 协议或者极端注重效率的协议比较青睐的负载类型。

生命周期 STATEFUL/STATELESS

STATEFUL - Server 具有自己的状态(例如包含一个或者多个FSM)并且通过API 暴露,对API 调用会改变Server 的状态。这对Client 在流程控制和错误处理上提出了更高的要求,因为Client 需理解Server 的状态流转流程并且确保某些状态流转的发生(比如某个FSM 的终态)。

STATELESS - 目前比较流行的API 设计理念。Server 不再对外暴露其状态流转,其内部可以更好地封装流程处理,并且提供更加易用的API。这种设计也可以更好的支持Server 的横向扩展(Scale Out)和负载均衡(Load Balance)。

作用范式 COMMAND/DECLARITIVE

和生命周期紧密相关,STATEFUL 的设计通常对应命令式的API,而STATELESS 的设计则对应声明式API。

COMMAND - 命令式API 自古以来就非常契合程序思维,给计算机一条指令,计算机执行并返回结果。RPC 也是命令式API 的一个典型表现。

DECLARITIVE - 声明式API 现在越来越流行,因为它提供了更好的封装,Client 可以实现的更简单,并因此简化程序间的集成。声明式API 仅声明目标或者目标状态,如何达成目标由Server 自己决定。