# 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 自己决定。
