来源:极链科技作者:刘聪说到接口的设计大部分人第一个想到的可能是REST;的确,REST是目前最为普遍的一种接口设计方式,并且作为一个优秀的接口设计标准而被广泛使用,但是除此之外,我们也不应该忘记还有其他的选项。除了REST,我们还有rpc(或者grp),最近大火GraphQL,以及webhooks. 为了好的了解这几种设计以及背后的优缺点,我们一一做简单的介绍。
- REST
Resource:资源,那对于程序来讲就是数据;
Representational:表现形式,我们在web开发中常用的传输类型比如TXT、HTML、JSON、XML、JPEG等;
State Transfer:状态变化,对应的是HTTP协议中的动词(常用的动词如:GET POST PUT PATCH DELETE);
REST基于HTTP,所以也是无状态的,以HTTP的各种动词来定义约定一系列的URL来操作资源;它描述的是网络中client与server的一种交互形式。
但是我们在谈REST的时候其实并不是谈论REST本身,而是RESTful API,即REST 风格的网络接口设计;来看几个最基础RESTful API的URL:
- GET /api/users : 列出所有用户
- POST /api/users : 新建一个用户
- GET /api/users/ID : 获取一个用户的指定信息
- PUT /api/user/ID : 更新某个指定用户的信息(全部信息)
- PATH /api/users/ID :更新某个指定用户的信息(部分信息)
- DELETE /api/users/ID : 删除某个用户
REST的优点也比较明显:客户端与服务器分离,简化服务器逻辑以及提高可伸缩性;无状态,降低服务器资源使用(相对于有状态的长连接),同时提高服务器的可扩展性;由于不同的信息返回时可以分开标记是否可以缓存,使得客户端可以重用之前的信息,减少客户端与服务端的交互次数。
- RPC / gRPC
常用的一些分布式RPC框架有Dubbo、Thrift、RPCx等;不过我们这里并不打算介绍这些框架,主要介绍一下谷歌开源的一个rpc框架:gRPC。
gRPC相对于常用的RPC框架最大的特点是使用了protobufs作为语言格式化数据,进一步提高了序列化和反序列化的速度,同时降低数据包的大小。Protobuf开源已久,它提供了一种灵活、高效、自动序列化结构数据的机制,作用与XML、JSON等格式类似,但是使用二进制传输,序列化/反序列化的速度快,压缩效率高;而且Protobuf有强大的IDL(Interface
Description Language,接口描述语言)和相关的工具,用户写好.proto描述文件之后可以编译成多种语言。
gPRC另外一个特点是使用HTTP2,性能比HTTP1.1好很多,我们也可以简单了解下HTTP2的一些特性,为什么会比HTTP1.1性能好:
- 新的二进制格式。x都是基于文本解析,而因为文本表现形式的多样性,基于文本协议的格式解析天然存在健壮性的问题,而采用二进制格式后实现方便并且健壮。
- 多路复用。x每个请求要重新建立新的连接,而且每个浏览器都有会限制单个页面创建的连接数,而在HTTP2.0中多个请求可以复用一个连接。
- header压缩。目前x中的header信息每次都会重复发送,造成很大的浪费。HTTP2.0使用encoder减少传输的header 大小,且通信双方都缓存一份包含了header信息的表,伺候的请求只需要发送差异数据,避免重复的传输。
- GraphQL
文章图片
事实上GraphQL跟REST也是可以共存的,甚至可以共同使用一些公共授权验证模块验证调用合法性。
可以找一个简单的例子看一下GraphQL是如何工作的,比如我们要查询某个部门下的成员, 用REST的风格可能如下:
curl -v http://api-host.com/api/deparment/:departmentId/members
含义明确,但是返回什么内容如果没有沟通过或者没有文档说明,客户端是不知道返回什么内容的。同样的API GraphQL的做法如下:
query {
departmentn( ) {
members(first: 100) {
edges {
node {
name avatarUrl
}
}
}
}
}
具体返回的结果如下:
{
"data": {
"department": {
"members": {
"edges": [
{
"node": {
"name": "member1",
"avatarUrl": "https://test/member1"
}
},
{
"node": {
"name": "member2",
"avatarUrl": "https://test/member2"
}
}
]
}
}
}
}
从上面返回的内容可以看出,不会包含多余的内容,只返回request需要的内容。目前使用GraphQL的一个比较典型和熟知的例子就是github, github api v4 开始使用graphql,有兴趣可以了解下。
实现了GraphQL标准的客户端有很多,比如Relay或者appollo-client等。
- Webhook
比如你的客户端要长期监听某个任务的状态,如果按照正常的api调用的方式去做,那么必须不停得轮训服务器来获取当前状态;使用webhook则无需轮训,只需要等待服务器推送信息过来,客户端更新即可。git webhook其实也是这方面的应用。
结论
从以上的介绍可以看出,其实并没有哪种方法是必然优于另外一种的,每一种方法都有其适 用的场景。
REST: 无状态的数据传输,适用于通用、快速迭代和标准化语义的场景;虽然 RESTful API的设计风格是目前最普遍的方式,但是其实也并不是所有场景都适合, 比如遇到有复杂操作要求的前端交互,用起来就很别扭,像获取、删除多个对象;对于一些内部的系统,大多数开发更注重效率,而不是完全遵守这样的规范,真正完全遵守的场景确实也不多。
gRPC:对于前端跟服务器端交互来说HTTP 无状态的方式其实是最方便的,前后端完全解耦,系统更容易扩展。而对于一些服务端之间的通信,比如现在的微服务,大部分共用服务可能并不需要对外开放,只在内部进行相互调用,这种情况下gRPC是个不错的选择,而且也能满足服务器之间调用对性能和延时要求高的需求。
GraphQL:GraphQL 并不是作为REST的替代方案,如果指望使用GraphQL能答复提升开发效率,那可能不现实;其实让客户端来选择返回的内容增加了客户端的工作量,把服务器端的一些工作转移出去了。不过相对于那些相对成熟的对外开放的OpendAPI,GraphQL更合适,比如github api,可以让开发者觉得获取内容其实是非常高效的,因为对于稳定的内容,有选择的去获取数据比全量返回从效率上能提升不少。
Webhook:其实从字面上理解这种应用场景就是需要服务器主动推送的地方,比如没有前端界面作为中转的服务,或者是不适合前端来操作的强安全页面(如支付),算是在特殊场景下的应用方式,毕竟相对于无状态的方式,维持连接来做推送还是开销不小,会增加不少的服务器端压力。
【AI|几种API设计方法REST、gRPC、GraphQL及WebHook的对比和选型】在技术选型上可能是一个项目开始的时候最艰难的事,不同的应用场景要选择不同的技术解决 方案,毕竟在软件开发上没有银弹,合适的才是最好的。