What is GraphQL?

GraphQL是Facebook两年前发布的一个后端API的查询语言(即名称中的QL的含义),但不要被它名字中的Graph所迷惑,它和图表并没有什么关系。

关于API的查询其实我们并不陌生,比如http://localhost/messages?limit=20&output_mode=JSON,url中的问号后面的部分会被RESTful的后端解析成参数,进而可以返回对应参数的结果。当然,传统的API查询只是在每一个endpoint(即url路径)下面来单独进行的,比如/messages下面需要一个按照日期排序的查询参数,而其他的endpoint则未必需要这个参数。

不同于RESTful的API设计模式中用不同的endpoint来表示不同的资源,GraphQL中所有的请求都会发送到同一个endpoint上(假设就叫/graphql),而把请求的目标等信息全部放在了请求参数当中(比如/graphql?query={messages})。

因此,GraphQL并不是重新定义了一种协议,它只是在现有协议上的一种查询语言,我们只需要在server端定义好schema,在client端只需要根据这些schema来发送查询的请求就可以了。

GraphQL的生态圈还是挺丰富的。在server端,GraphQL有很多语言的实现,比如JavaScript的GraphQL.js,在client端,关于ReactJS有专门的官方的实现叫做Relay

Why GraphQL?

在我有限的写前端代码的经验中,碰到过这样一种场景:

渲染某一个表格需要向后端发送两个请求,且后一个请求的路径依赖于前一个请求返回的结果。

这个场景带来的麻烦在于:

  1. 前端代码逻辑复杂。本身两个请求都是异步的,就涉及到异步回调处理;每个请求都需要对请求失败做相应的处理,这块也很容易产生bug。
  2. 开销更大。相比于通过一个请求拿到所需的数据,发送两个请求显然更加耗时,且对后端负载更大。

遇到这种情况,通常的解决方案是新建一个后端的endpoint来处理这个请求,这样前端就可以通过一个请求来拿到所有需要的数据了,但带来的问题是这个新的endpoint和原来的两个endpoint是完全冗余的,随着前端需求的增加和变化,这些冗余的路径会越来越多,文档也会变得混乱。当然,还有一种比较蠢的解决方案,后端提供一个大而全的endpoint包含尽量多的数据,这样每次前端只需要访问这一个endpoint就可以了,但这样做效率可能还没有多发几次请求来得高(毕竟这个请求返回的数据很多,又会频繁访问,开销必然更大),只是前端逻辑处理简单了一些。

有没有一种解决方案,既可以简化前端代码的请求处理,又能提高请求的效率,并让后端API不会变得冗余和复杂?用GraphQL啊。GraphQL就是提供了一个“大而全”的endpoint,且它可以根据请求的查询语句只返回必要的数据。

当然,GraphQL带来的好处不止这一点,比如它还让API的版本升级变得很简单,比如明确的数据类型定义可以减少类型相关的问题(想起了Avro),具体可以读一读GraphQL vs REST: Overview

以我现在有限的接触,我也不好下结论GraphQL究竟是会像RESTful这么流行,还是只是昙花一现。但至少它提供了一种思路来解决前后端交互产生的一些问题,况且它和现有的RESTful的API还可以兼容(Wrapping a REST API in GraphQL),何乐而不一试呢?