开源 Netflix 域图服务框架:用于 Spring Boot 的 GraphQL
Netflix 开发了一个域图服务 (DGS) 框架,现在它是开源的。DGS 框架简化了 GraphQL 的实现,适用于独立和联合 GraphQL 服务。我们的框架因我们的大规模使用而久经沙场。
通过开源该项目,我们希望为 Java 和 GraphQL 社区做出贡献,并向所有将使用该框架的人学习并与他们合作,以使其在未来变得更好。
DGS 框架的主要特点包括:
基于注解的 Spring Boot 编程模型
将查询测试编写为单元测试的测试框架
Gradle 代码生成插件,用于从 GraphQL 模式创建 Java/Kotlin 类型
与 GraphQL Federation 轻松集成
与 Spring Security 集成
GraphQL 订阅(WebSockets 和 SSE)
文件上传
错误处理
自动支持接口/联合类型
Java 的 GraphQL 客户端
可插拔仪表
为什么我们需要 DGS 框架
大约在 2019 年春季,Netflix 开始了一场实现联合 GraphQL 架构的伟大冒险。我们的同事写了一篇Netflix 技术博客文章,描述了这种架构的细节。过渡到新的联合架构意味着我们的许多后端团队需要在我们的 Java 生态系统中采用 GraphQL。您可能还记得之前的博客文章,Netflix 已经在 Spring Boot 上进行了标准化以进行后端开发。因此,为了使这种联合架构取得成功,我们需要在 Spring Boot 中拥有出色的 GraphQL 开发经验。
我们在 Spring Boot 之上创建了我们的框架,它利用了graphql-java库。该框架最初旨在仅用于内部,专注于与 Netflix 生态系统集成以进行跟踪、日志记录、度量等。但是,框架的适当模块化始终是首要考虑因素。很明显,我们构建的大部分框架实际上并不是 Netflix 特定的。该框架主要是构建 GraphQL 服务的一种更简单的方法,无论是独立的还是联合的。
模式优先开发
Schema 是 GraphQL 如此强大且与 REST 不同的原因。GraphQL 模式根据 Query 和 Mutation 操作及其相关类型和字段来描述 API。API 用户可以精确地指定要在查询中检索哪些字段,从而使 GraphQL API 非常灵活。
GraphQL 开发有两种不同的方法;模式优先和代码优先的开发。通过模式优先开发,您可以使用GraphQL 模式语言手动定义 API 的模式。您的服务中的代码仅实现此架构。
使用代码优先开发,这种情况下没有模式文件。相反,模式是在运行时根据代码中的定义生成的。
我们的框架支持模式优先和代码优先两种方法。在 Netflix,我们非常喜欢模式优先的开发,因为:
架构设计是开发人员体验的前沿和中心。
它为工具使用模式提供了一种简单的方法。
使用模式差异时,向后不兼容的更改更加明显。在联邦 GraphQL 架构中工作时,向后兼容性更为关键。
尽管从代码生成模式可能稍微快一些,但花时间以人类可读、协作的方式设计模式是非常值得为更好的 API 付出努力的。
行动框架
该框架的核心围绕着 Spring Boot 开发人员熟悉的基于注解的编程模型。
我们从一个简单的模式开始。
要实现这个 API,我们需要编写一个数据获取器。
Show 类型是一个简单的 POJO,我们通常会使用Gradle的DGS 代码生成插件生成它。 使用@DgsData注释的方法实现了字段的数据获取器。请注意,我们不需要每个字段的数据获取器,我们可以返回 Java 对象,其余的由框架处理。框架还有许多便利,例如本示例中使用的@InputArgument注释。
这段代码足以让 GraphQL 端点运行。只需启动 Spring Boot 应用程序,即可使用/graphql端点以及开箱即用的/graphiql上的GraphiQL查询编辑器。尽管此示例中的代码很简单,但如果我们使用联合类型、使用@Secured或使用扩展点添加指标和跟踪,它看起来并没有太大的不同。该框架负责所有繁重的工作。
另一个关键特性是支持轻量级查询测试。这些测试允许您执行查询,而无需使用 HTTP 端点。测试的外观和感觉就像普通的 JUnit 测试。
融入 GraphQL 服务器生态系统
那么 DGS 框架究竟如何适应现有的 GraphQL 生态系统呢?当前的生态系统包括服务器、客户端、联合网关和工具,以帮助进行查询测试、模式管理、代码生成等。在使用 JVM 构建 GraphQL 服务器时,有模式优先和代码优先的库可用.
一个流行的代码优先库是用于 Kotlin的graphql-kotlin 。graphql-java最流行用于在 Java 中实现模式优先的 GraphQL API,但它被设计为一个低级库。graphql -java-kickstart starter 是一组用于实现 GraphQL 服务的库,并在 graphql-java 之上提供了graphql-java-tools和graphql-java-servlet。
无论您使用 Java 还是 Kotlin,我们的框架都提供了一种在 Spring Boot 中构建 GraphQL 服务的简单方法。它可用于构建独立服务以及在 Federated GraphQL 的上下文中。
联邦
DGS 框架提供了一种通过联合实现 GraphQL 服务的便捷方式。联合允许服务共享由网关公开的统一图。通常,服务使用Apollo 的联合规范定义的 @extends 指令共享和扩展统一模式中定义的类型。这是跨微服务拆分大型单体 GraphQL 架构所有权的有效方法。
对于传入查询,联合网关构建查询计划以调用所需的服务来完成该查询。反过来,每个服务都需要能够响应 entities 查询,以便部分完成对其拥有的数据的查询。
下面是一个评论服务示例,它使用评论字段扩展了之前定义的 Show 类型:
鉴于此模式,Reviews DGS 需要为联邦显示类型实现一个解析器,其中填充了评论字段。这可以使用@DgsEntityFetcher注释轻松完成,如下所示:
该框架还可以轻松地使用代码生成来测试联合查询,以便基于模式为服务生成entities查询。
框架架构
从开发的早期开始,我们就专注于代码的良好模块化。这是一个重要的设计选择,可以在不影响我们内部团队的情况下开源大部分框架。我们还不能使用 Java 9 中引入的模块系统,因为 Netflix 的很多应用程序仍在使用 Java 8。但是,在 Gradle api和实现模块的帮助下,我们能够创建一个干净的模块结构。在 Netflix,我们为 Spring Boot 提供了许多扩展来与我们的基础架构集成。我们将此 Spring Boot 称为 Netflix。DGS 框架建立在标准的开源 Spring Boot 之上。最重要的是,我们有一些模块与我们的特定基础设施集成,并且仅使用核心框架提供的扩展点。
以下是模块如何组合在一起的示意图:
分布式跟踪和指标
在 Netflix,我们为跟踪、指标、分布式日志记录和身份验证/授权等功能提供自定义基础架构。如前所述,DGS 框架与此基础架构集成以提供开箱即用的无缝体验。虽然这些功能不是开源的,但它们很容易添加到框架中。
该框架支持在graphql-java库中定义的Instrumentation类。通过实现Instrumentation接口并对其进行注释@Component,框架能够自动获取它。您可以在我们的文档中找到一些参考示例。




