今年我一直比较关心 Facebook 的几个开源项目。一开始可能还是跟风和赶时髦心理——听说 React 比较火,为了不落伍,就尝试写了点玩具代码,用下来的感觉是极好的……然后还有个附带结果就是,我对 Facebook 的好感度涨了不少。于是最近 GraphQL 出来之后,也就迫不及待的要试一试。不过因为现在工作比较忙,也可能是我越来越懒了,这回主要还是看了一些视频跟文档。当然,基本还算是了解了这个东西的。
GraphQL 是一种查询语言,Facebook 发布的是一个 Specification,也就是一些文档,而并非一个框架或库(虽然确实 Facebook 也开源了一个基于 node.js 的参考实现 graphql-js)。给我的感觉就是这个东西是有高度的:如果是框架或者工具库,那么他可能作为工具可以提供便利。而一种查询语言,其实包含的是一种设计的思想,如果这种设计真的有优越性,那么它带来的影响将比一个框架要来的大。
API 设计的问题
认识 GraphQL 之前,可以先回顾一下其他的 API 形式。
RESTful 是一种被推崇的设计,现在很多服务对外提供的接口都是这种形式:服务提供的数据被抽象成几种 resource,然后每种 resource 可以被 get/put/update/delete 等等动词操作,当然也可以用一些更有业务意义的动词比如 list/show/upload 之类(RESTful 的定义并非是严格的)。不同的 resource 之间可以有关系,如何表达关系则是一个需要权衡的问题。
以新浪微博的接口为例:statuses/public_timeline
接口返回用户能看到的公共 Timeline,其中每一条是一个 status 也就是一条微博。
那么这个 status 上必然是有 user 字段的,也就是有这条微博的作者信息,这就表达了一条微博和一个用户的关系。那问题是,public_timeline
接口上,每个 status 需要有 user 的哪些信息呢?最少,提供一个用户的 ID 就可以,因为根据 ID 我们可以通过另一个接口 users/show
来获取这个用户的其他信息。但是如果这么设计,可能很多常用的功能——比如显示这条微博作者的名字、头像,都需要访问两个不同的接口,对调用方不友好。换一种方式,我们当然也可以把 users/show
能返回的所有信息都嵌入到这个 status 里。这么做调用方确实是方便了,但大部分场景可能也并非需要访问用户的全部字段。接口暴露过多的冗余字段会浪费服务器网络带宽,对于移动客户端来说,浪费流量又是一个头疼的问题。于是这就要在字段间做一些选择,新浪微博的做法是嵌入了部分常用字段。
如果我们并非要对外提供通用的 API,而是给自己的前端、移动端提供接口,那么 Custom Endpoint 的形式也是很常用的设计。所谓 Custom Endpoint,就是专事专办,为每一项业务场景提供单独的接口。还是以微博为例,如果我们要做的客户端显示 Public Timeline 时只需要展示作者的名字和头像,那么接口中可以只包含这两个字段。这样调用起来一次就能得到需要的信息,也不存在多余字段浪费资源的问题。
然而这样的设计也有一些弊端。假如之后需求变动需要增加字段,那么从前到后都需要升级。通用性也不够,很多情况下类似的功能,可能还要给电脑跟移动端做两个相似的接口,最后的情况就是接口越来越多。另外,从服务端来考虑,我们定义了很多相似的结构和逻辑:某个接口里的用户结构体是名称、头像,另一个可能是名称、头像和粉丝个数,看起来差不多又未必能共用。相关的逻辑也可能差不多,却还是未必能复用。
GraphQL 是什么?
GraphQL 就是另一种设计,也许可以解决以上两种设计的问题。
嗯,又挖坑不填了,这文怕是写不下去了。