架构
架构Code-first 的 GraphQL 服务器

Code-first 的 GraphQL 服务器

GraphQL 模式通过公开可对服务执行的类型、字段和变更集合,定义了 GraphQL 服务的契约。在创建 GraphQL 服务时,我们可以选择以下两种方式之一:

  • 以模式作为唯一可信来源,让所有实现代码与其定义保持一致
  • 以代码作为唯一可信来源,将模式作为从代码生成的产物

无论哪种方式,我们都能获得一个完全可用的 GraphQL 服务,但根据所选方式的不同,未来能够实现的功能多寡以及实现的难易程度也会有所差异。这两种方式分别被称为「schema-first」(更准确的叫法是「SDL-first」)和「code-first」。

Gato GraphQL 采用 code-first 方式。下面来看看原因。

Gato GraphQL 采用 code-first 的原因

在 code-first 方式中,我们首先编写解析器,然后以代码作为唯一可信来源,将模式作为产物生成。也就是说,模式通过运行脚本来创建,而不像 SDL-first 那样手动创建。由于 code-first 同样具有模式,因此 SDL-first 所提供的重要功能在 code-first 中一样都不会缺少。

然而,code-first 相比 SDL-first 额外提供了一项重要功能:支持动态模式。动态模式可以根据上下文改变其形状和属性,并在运行时通过代码进行控制。事实上,Gato GraphQL 提供的所有出色功能,都是其采用 code-first 带来的直接成果。

code-first 的优势

动态模式提供了以下诸多优势(不限于此):

模式的可信来源是 GraphQL 所要求内容的超集。额外的属性(如全局字段、全局连接、全局指令和持久化片段)无需等待被纳入 GraphQL 规范(无论最终是否会被纳入),即可在 API 中直接使用。

由于可信来源不受限于模式,因此我们也可以为其他任何系统生成任意模式:GraphQL 只是目标之一。例如,可以从同一可信来源为 REST 服务生成 JSON-schema。

API 可以同时具备公开和私有属性,具体取决于用户是否已登录及其登录角色,也可以根据其他属性(例如用户是否已付费成为 PRO 会员)来提供多寡不同的字段。

类型无需提前知道将解析哪些字段。字段解析器通过 publish-subscribe 模式将自身关联到类型解析器,且字段解析器可以覆盖其他字段解析器。这一特性使 API 具备极强的可扩展性,让我们能够为 API 编写通用代码,同时在应用层针对特定客户端或项目进行定制。

一个字段可以由不止一个、而是多个字段解析器来处理:链中的每个字段解析器可在运行时根据某些属性决定是否处理该字段,或将其传递给链中的下一个解析器。例如,只有在传入字段参数 "source: testing" 时才会启用某个特殊字段解析器,从而可以在正式发布前先在生产环境的少数站点上进行测试;同样的策略还可以在不引发其他地方意外副作用的情况下,为特定客户端或环境快速修复 bug。

类型和接口可以自动添加命名空间,以避免与第三方发生冲突。