什么是 GraphQL
GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。
一个简单的例子
1 | // 描述数据 |
GraphQL 的特征
- 可描述性的:使用 GraphQL,你获取的都是你想要的数据,不多也不会少
- 分级性的:GraphQL 天然遵循对象间的关系,通过一个简单的请求,我们可以获取到一个对象及其相关的对象,比如说,通过一个简单的请求,我们可以获取一个作者和他创建的所有文章,然后可以获取文章的所有评论
- 强类型的:使用 GraphQL 的类型系统,我们可以描述能够被服务器查询的可能的数据,然后确保从服务器获取到的数据和我们查询的一致
- 不做语言限制:并不绑定于某一特定的语言,实际上现在已经有一些不同的语言有了实践;
- 兼容于任何后台:GraphQL 不限于某一特定数据库,可以使用已经存在的数据,代码,甚至可以连接第三方的 APIs
- 好反省的:GraphQL 服务器能够查询架构的细节
Type
对于数据模型的抽象是通过 Type 来描述的,每一个 Type 有若干 Field 组成,每个 Field 又分别指向某个 Type。
GraphQL 的 Type 简单可以分为两种,一种叫做 Scalar Type(标量类型),另一种叫做 Object Type(对象类型)。
Scalar Type
GraphQL 中的内建的标量包含,String、Int、Float、Boolean、Enum,可以通过 Scalar 声明一个新的标量,标量是 GraphQL 类型系统中最小的颗粒。
Object Type
对象类型用来抽象一些复杂的数据模型
1 | type User { |
Type Modifier
类型修饰符有两种,分别是 List 和 Required ,它们的语法分别为[Type]和 Type!, 同时这两者可以互相组合,比如[Type]!或者[Type!]或者[Type!]!,它们的含义分别为:
- 列表本身为必填项,但其内部元素可以为空
- 列表本身可以为空,但是其内部元素为必填
- 列表本身和内部元素均为必填
Schema
Schema 是用来描述对于接口获取数据逻辑的,我们不妨把它当做 REST 架构中每个独立资源的 uri 来理解它,只不过在 GraphQL 中,我们用 Query 来描述资源的获取方式。因此,我们可以将 Schema 理解为多个 Query 组成的一张表。
Query
下面三种基本查询类型是作为 Root Query(根查询)存在的,对于传统的 CRUD 项目,我们只需要前两种类型就足够了,第三种是针对当前日趋流行的 real-time 应用提出的。
我们按照字面意思来理解它们就好,如下:
- query(查询):当获取数据时,应当选取 Query 类型
- mutation(更改):当尝试修改数据时,应当使用 mutation 类型
- subscription(订阅):当希望数据更改时,可以进行消息推送,使用 subscription 类型
以 REST 和 GraphQL 的角度举例:
Rest 接口
1 | GET /api/v1/articles/ |
GraphQL Query
1 | query { |
Resolver
Resolver(解析函数)用来提供相关 Query 所返回数据的逻辑。GraphQL 中,Query 和与之对应的 Resolver 是同名的。
Resolver 本身的声明在各个语言中是不一样的,因为它代表数据获取的具体逻辑。它的函数签名(以 js 为例子)如下:
1 | function(parent, args, ctx, info) { |
其中的参数的意义如下:
- parent: 当前上一个 Resolver 的返回值
- args: 传入某个 Query 中的函数(比如上面例子中 article(id: Int)中的 id)
- ctx: 在 Resolver 解析链中不断传递的中间变量(类似中间件架构中的 context)
- info: 当前 Query 的 AST 对象
Resolver 内部实现对于 GraphQL 完全是黑盒状态。这意味着 Resolver 如何返回数据、返回什么样的数据、从哪返回数据,完全取决于 Resolver 本身,基于这一点,在实际中,往往把 GraphQL 作为一个中间层来使用,数据的获取通过 Resolver 来封装,内部数据获取的实现可能基于 RPC、REST、WS、SQL 等多种不同的方式。同时,在对一些未使用 GraphQL 的系统进行迁移时(比如 REST),可以很好的进行增量式迁移。
优点
- 网络开销低,可以在单一请求中获取 REST 中使用多条请求获取的资源
- 强类型 Schema(约束意味着可以根据规范形成文档、IDE、错误提示等生态工具)
- 特别适合图状数据结构的业务场景(比如好友、流程、组织架构等系统)
缺点
- 本身的语法相比较 REST 和 RPC 均复杂一些
- 实现方面需要配套 Caching 以解决性能瓶颈
- 对于 API 的版本控制当前没有完善解决方案(社区的建议是不要使 API 版本化)
- 仍然是新鲜事物,很多技术细节仍然处于待验证状态
参考资料
- GraphQL
- RPC vs REST vs GraphQL
- 一篇文章帮你理清 GraphQL 的核心概念(译)
- GraphQL 规范