本文是 《全栈开发 GraphQL + Flutter 最佳实践,文章系列》 的第 3 篇。主要介绍 GraphQL 的设计理念,及其优劣。
什么是 GraphQL?
GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。
一切皆是图(Graph)
使用 GraphQL,我们可以将所有的业务建模为图
图是将很多真实世界现象变成模型的强大工具,因为它们和我们自然的心智模型和基本过程的口头描述很相似。通过 GraphQL,我们会把自己的业务领域通过定义 schema 建模成一张图;在我们的 schema 里,我们定义不同类型的节点以及它们之间是如何连接的。在客户端这边,这创建了一种类似于面向对象编程的模式:引用其他类型的类型。在服务器端,由于 GraphQL 定义了接口,我们可以在任何后端自由的使用它(无论新旧!)。
共同语言
GraphQL 并不是一种协议或者规范。它是一种语言,一种前端后端交流沟通所使用的语言。这种语言用精炼简洁的语法,降低了前后端的沟通成本。此外,这门语言还是非常严谨的,并且它的可读性较高。这就降低沟通中产生误会的可能性,减少了 Debug 的时间。
熟悉这门语言的开发者看了项目的 schema 后,立刻就知道如何发送请求,并且返回值是什么格式的。这一切甚至都用不到 2 分钟,而这个过程还是一个人独立完成的,不需要与后端沟通。
演示《掘金 APP》
我们用一个页面来展示 GraphQL 有何不同之处。目前很多 APP 都有个类似的首页,顶部是一些标签,中间显示被选中标签下的内容列表:
一般情况下,这个页面会有两个接口:
- 获取全部标签 - 主要用于展示顶部标签栏
- 根据标签获取内容列表 - 主要用于展示中间的博文列表
客户端首次进入到这个页面时会发两个请求,然后将两个请求的结果拼接起来,接着刷新页面。这是传统的做法。
那么 GraphQL 是如何实现这种功能的?
定义一个 schema:
Query 是一个入口,我们可以通过 Query 下的 tags 方法拿到部分标签:
执行:
这也是之前提到过的第一个接口“获取部分标签”。
我们再来看看第二个接口“通过标签获取博文列表”是如何实现的。
这里可以通过 Query 下的 tag 方法来获取 Tag,然后使用 Tag 下的 posts 方法来获取相应的博文列表:
这样我们就能单独调用这两个接口了。
One more thing!
此外,GraphQL 可以在一个请求里面同时获取到这两个资源:
Good Job!
不过这里还遗留了一点问题,可能细心的同学已经发现了,就是:
博文作者相关信息缺失,用户名和头像 URL 没有返回。我们现在就来修复它,通过 Post 下的 user 字段把这些信息拉取出来:
完成!
举一反三
如果我们有一个《全部标签》页面。另外,这也页面还要预览每个标签下的前 4 个博文,那要怎么做呢?
反思
当今很多页面都需要向多个资源发送请求。有的页面甚至要发 3 个以上的请求, 而且请求之间可能存在依赖关系,即:后一个请求依赖于前一个请求的结果。
如果我们使用 GraphQL,只要 schema 设计得当,一个页面至少可以减少一半的请求数,而且不需要后端单独为页面出定制化的接口。
由于 GraphQL 请求配置相当灵活,我们可以通过 schema 的定义, 自己组合出各式各样的请求。这在一定程度上也减少了后端的工作量。项目做到中后期,我们会发现许多新增的需求,都不需要单独出接口,复用之前的接口就行了。例如:举一反三中提到的《全部标签+预览标签下博文》的需求。
GraphQL 优势
- 请求你所要的数据,不多,也不少
- 节省带宽
- API 演进无需划分版本
- 健全的类型系统
- 自动生成文档
- 减少前后端的沟通成本
- 工具
- GraphiQL - GraphQL 游乐场
- Code Generater - 前端(Web 和 原生移动端)生成请求代码,而且入参和返回值都是强类型的
GraphQL 劣势
- 学习成本,因为需要学一门新的语言 GraphQL
- 团队合作模式改变
- 前端压力变小,但服务器压力变大,因为部分前端压力转移到服务器上去了
- 获取数据的效率下降,需要借助 dataloader 这样的工具来做优化
谁在使用 GraphQL?
- GitHub
- PayPal- Scaling GraphQL at PayPal
- Netflix - Our learnings from adopting GraphQL
- The New York Times - The New York Times — Now On Apollo
- Nerdwallet - Getting started with GraphQL and Apollo (Part 1)