GraphQL入门指导

什么是GRAPHQL

GraphQL是API的查询语言和运行时,用于使用现有数据完成这些查询。 GraphQL提供了API中数据的完整且易于理解的描述,使客户能够准确地询问他们需要什么,仅此而已,使API随着时间的推移更容易发展,并支持强大的开发人员工具。

GraphQL 与 RESTful 有什么区别?

  • 首先放上一张来自于 graphql.org 的图片。REST 与 GraphQL 都是服务端所承载的系统对外的服务接口,因此两者肯定是可以共存的,甚至可以共用一套 Authorization 等业务逻辑。

    RESTful的一些不足:
  • 扩展性,单个RESTful接口返回数据越来越臃肿
    比如获取用户信息/users/:id,最初可能只有id、昵称,但随着需求的变化,用户所包含的字段可能会越来越多,年龄、性别、头像、经验、等级,等等等等。

而具体到某个前端页面,可能只需要其中一小部分数据,这样就会增加网络传输量,前端获取了大量不必要的数据。

  • 某个前端展现,实际需要调用多个独立的RESTful API才能获取到足够的数据
    比如一个文章详情页,最初可能只需要文章内容,那么前端就调用/articles/:aid获取到文章内容来展现就行了

但随着需求的演进,产品可能会希望加上作者信息(昵称、头像等),这时前端又需要在获取文章详情后,根据其中的作者id字段继续获取作者相关的信息,/user/:uid

然后,需求又变化了,产品希望在加上这篇文章的评论,这时前端需要继续调用/comment/:aid来拉取评论列表

对于Web前端而言,由于ajax技术的存在,这种的请求数据方式,也就开发上稍微麻烦些,并不会造成太大的问题;但对于App来说,渲染的方式不同,必须要拉取的全部的数据之后,才能绘制界面,就会导致这个界面必须要等到所有3个RESTful接口的返回数据都拿到,才能进行绘制。

GraphQL的一些优点

  • 所见即所得
    查询的返回结果就是输入的查询结构的精确映射
    查询:
    1
    2
    3
    4
    5
    6
    {
    books(id: 3) {
    id
    name
    }
    }

返回:

1
2
3
4
5
6
7
8
{
"data": {
"user": {
"uid": "1",
"name": "xxx"
}
}
}
  • 减少网络请求次数
    如果设计的数据结构是从属的(例如,上文中书的作者信息),直接就能在查询语句中指定:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    {
    books(id: 3) {
    id,
    name,
    author {
    id,
    name
    }
    }
    }

即使数据结构是独立的,也可以在查询语句中指定上下文,只需要一次网络请求,就能获得资源和子资源的数据(例如,上文中书和作者信息)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
books(id: 3) {
id,
name,
author {
id,
name
}
},
allAuthors {
id,
name
}
}
  • 代码即文档
    GraphQL会把schema定义和相关的注释生成可视化的文档,从而使得代码的变更,直接就反映到最新的文档上,避免RESTful中手工维护可能会造成代码、文档不一致的问题。

  • 参数类型强校验
    RESTful方案本身没有对参数的类型做规定,往往都需要自行实现参数的校验机制,以确保安全。

但GraphQL提供了强类型的schema机制,从而天然确保了参数类型的合法性。

GraphQL 能做到修改数据吗?

看了上面的 query 的例子,你肯定很好奇,graphql 这种看上去好像只为查询而存在的语言,是不是有办法做到修改数据呢?

答案是:能。

仅仅为了使得 GraphQL 这个 data platform 变得更加完整,GraphQL 标准中加入了一种操作符,名为 mutation。因为我觉得这种设计确实比较一般,此处就不举例了,详情见:http://graphql.org/learn/queries/#mutations

令人期待的 subscription

如何在浏览器中接受服务端的推送信息是个老生常谈的问题。从最初的轮询,到后来的 WebSocket。如今 GraphQL 也计划引入除了 query, mutation 以外的第三种操作符 subscription,以便于直接接受服务器推送数据。在 2015 年底 GraphQL 官方发布了一篇博文:Subscriptions in GraphQL and Relay 来介绍 subscription 在他们的 iOS 和 Android App 中的应用。可惜的是相关的代码仍未开源,目前开源社区能找到的解决方案目前只有 Apollo 社区为 Node.js 写的 graphql-subscriptions。

GraphQL 有什么缺点?

  • N + 1 问题
    以下解决方案仅针对关系型数据库,如果你的项目中使用的是 NoSQL,可能解决方案有较大差别。

针对一对一的关系(比如我上面举例中提到的这个 User 与 UserScore 的关系),在从数据库里抓取数据时,就将所需数据 join 到一张表里。别等着 ORM 框架替你懒加载那些你需要的数据。
针对多对一或者多对多的关系,你就要用到一个叫做 DataLoader 的工具库了。其中,Facebook 为 Node.js 社区提供了 DataLoader 的实现。DataLoader 的主要功能是 batching & caching,可以将多次数据库查询的请求合并为一个,同时已经加载过的数据可以直接从 DataLoader 的缓存空间中获取到。这个话题要是展开说也得写一篇新的文章了,此处不多赘述。

有什么可以快乐地调试 GraphQL 接口的方法?

GraphiQL / live demo

使用 GraphiQL 可以很容易地让人感受到“代码即文档”的快乐。

扩展阅读: https://graphql.org/ https://www.howtographql.com/graphql-python/0-introduction/