使用GraphQL设计可扩展的Java API

你是否曾想过在应用程序中获取数据是否有比 REST API 更好的方式?在后端开发中,GraphQL已经成为一个强大的替代方案,提供了一种更灵活、高效的数据获取方法。对于熟悉Java的开发人员来说,将GraphQL集成到现代后端可以打开通往各种用例的可伸缩、高性能API之门。

本博客将探讨GraphQL和REST之间的关键区别,突出使用GraphQL进行数据获取的独特优势,并指导您通过一个真实示例实现在Java中创建一个GraphQL API

什么是GraphQL?

GraphQL是用于API的查询语言和用于执行这些查询的运行时。与REST不同,固定端点返回预定义数据,GraphQL允许客户端请求它们需要的确切数据。这种细粒度使得GraphQL在处理复杂或数据密集型应用程序时非常高效。

GraphQL方法的优势:

  • 数据粒度获取:客户端可以查询姓名和职务,而无需检索不必要的字段如部门。
  • 嵌套查询:在单个查询中获取经理详情以及员工信息。
  • 基于模式驱动开发:模式充当合同,使API演进更加容易。

什么是REST API?

表述性状态转移(REST)是用于构建API的一种架构风格。它使用标准的HTTP方法,如GET、POST、PUT和DELETE来执行CRUD操作。REST以其简单性和广泛应用而闻名。

REST的局限性:

  • 数据过度获取或不足获取。
  • 需要多个端点和版本控制以适应更改。
  • 没有内置的实时能力。

GraphQL与REST API:有何区别?

GraphQL和REST是构建API的两种流行方法,各有其优势。虽然REST多年来一直是标准,但GraphQL在数据检索和前后端团队合作方面提供了更大的灵活性和效率。

主要区别

  • 与REST不同,GraphQL将数据检索整合到单个查询中,并减少了对版本控制的需求,因为客户端指定数据需求。
  • 虽然REST使用HTTP状态代码指示成功或错误,但GraphQL始终返回200 OK状态,并通过响应主体传达错误。
  • GraphQL还支持通过订阅进行实时更新,而REST则缺乏内置的实时支持。
  • 尽管 REST 已经得到广泛的建立并有许多工具,但 GraphQL 的环境迅速发展,提供了强大的工具,如 GraphiQL,以便更容易进行开发。
  • 最后,虽然 REST 使用标头进行缓存,但由于动态查询,GraphQL 需要更高级的技术,但提供了诸如持久化查询之类的选项,以实现有效的缓存。

核心 GraphQL 概念

1. 模式定义语言(SDL)

GraphQL 有自己的类型系统,用于定义 API 的模式。编写模式的语法称为模式定义语言(SDL)。

2. 查询 vs. 变更 vs. 订阅

  • 查询 用于从服务器获取数据。与使用多个固定端点的 REST 不同,GraphQL 使用单个端点,客户端在查询中指定所需的数据,提供了灵活性。
  • 变更 用于在服务器上修改数据,例如创建、更新或删除数据。它们允许客户端向后端发送更改,并且对于需要编写数据的应用程序至关重要。
  • 订阅 通过保持客户端和服务器之间的稳定连接实现实时更新。当发生订阅的事件时,服务器会向客户端推送更新,提供连续的数据流,不同于查询和变更,后者遵循请求-响应循环。

3. GraphQL 模式

它定义了可以查询或修改的数据结构,充当服务器和客户端之间的合约。它指定可供客户端访问的类型、字段和关系。模式通常包括特殊的根类型:用于数据检索的查询、用于修改数据的变异和用于实时更新的订阅。这些类型共同定义了API的功能以及客户端如何与之交互。

4. 解析器:将GraphQL查询映射到数据

解析器是处理GraphQL服务器中数据获取逻辑的函数。模式中的每个字段都与一个解析器相关联,该解析器确定如何检索或计算该字段的数据。执行查询时,服务器会为请求的字段调用适当的解析器。解析器可以返回标量或对象,如果返回对象,则会继续执行子字段,如果返回标量,则会完成执行。如果返回null,则执行停止。解析器对于将GraphQL查询映射到实际数据源至关重要。

在Java中使用GraphQL的优势

  1. 精确数据获取:仅查询所需数据,确保可预测和高效的结果。
  2. 单个请求获取多个资源:在一次查询中获取相关数据,减少多个API调用。
  3. 类型系统:通过类型和字段组织API,确保查询有效且错误清晰可见。
  4. 开发工具:使用诸如GraphiQL之类的工具增强生产力,利用类型定义进行更好的查询构建和调试。
  5. 无版本演进: 添加或弃用字段而不会破坏现有查询,使API易于维护。
  6. 灵活的数据集成: 创建一个统一的API,覆盖现有数据和代码,兼容各种存储引擎和语言。

在Java中设置GraphQL API

实际示例: 用户和订单

假设您正在为一个大型组织构建员工目录API。目标是允许客户端查询员工姓名、职位、部门,甚至他们的汇报层级关系。

1. 设置项目

使用Spring Tool Suite创建一个新的Spring Boot项目或访问Spring Initialiser。然后,将这些依赖项添加到pom.xml文件中:

XML

 

2. 创建您的实体

创建Java实体(例如,UserOrder),用于表示将通过GraphQL查询或更改的数据。例如:

Java

 

3. 创建存储库

创建与数据库交互的存储库:

Java

 

4. 创建服务类

创建服务类来处理业务逻辑:

Java

 

5. 创建 GraphQL 控制器

定义 GraphQL 控制器来处理查询和变更:

Java

 

6. 定义您的 GraphQL 模式

src/main/resources 目录中创建一个 schema.graphqls 文件:

Plain Text

 

7. 在 application.properties 中配置 GraphQL

可选地,在 scr/main/resources/application.properties 中配置 GraphQL 设置:

Properties files

 

8. 运行您的应用程序

使用 mvn spring-boot:run 或从您的 IDE 运行 SpringBoot 应用程序。一旦运行,您可以访问 /graphiql 端点。

9. 使用 GraphQL 查询进行测试

使用类似 GraphiQL 或 Postman 的工具测试 GraphQL API。

对于变更: 

Plain Text

 

输出:

Plain Text

 

对于查询:

Plain Text

 

输出:

JSON

 

高级 GraphQL 功能

1. 使用片段增强可重用性

片段基本上是为特定类型定义的可重用字段集。它是一个有助于改善 GraphQL 代码结构和可重用性的功能。

2. 使用参数化字段

在GraphQL中,字段可以接受参数,使查询更加动态和灵活。这些参数允许您过滤或自定义API返回的数据。

3. 使用GraphQL进行分页和排序

分页

分页在API设计中是一个棘手的话题。在高层次上,关于如何处理它有两种主要方法。

  • 限制偏移:通过提供要检索的项的索引来请求列表的特定块(实际上,您主要提供起始索引(偏移)以及要检索的项的计数(限制))。
  • 基于游标:这种分页模型稍微更高级一些。列表中的每个元素都与唯一ID(游标)相关联。然后,浏览列表的客户端提供起始元素的游标以及要检索的项的计数。

排序

使用Graphql API设计,可以返回根据特定标准排序的元素列表。有序

使用GraphQL的挑战和考虑

  • 复杂性:管理GraphQL模式和查询可能对简单数据模型或经验不足的团队构成挑战。
  • 性能问题:如果未经过优化,深度嵌套查询可能会对后端资源造成压力。
  • 缓存挑战:标准的基于REST的缓存策略不适用,需要定制解决方案。
  • 安全问题: 过度获取和恶意查询需要查询限制和其他保护措施。
  • 混合使用: 最适合复杂数据需求,通常与REST结合以实现更简单的操作。

结论

GraphQL为在Java中构建现代API提供了一种灵活高效的方法,使其成为动态和数据密集型应用的理想选择。其单一端点架构和强类型简化了API设计,同时确保了强大的性能。无论您是在创建简单的员工目录还是复杂的分析平台,GraphQL都能使开发人员轻松交付可扩展的解决方案。今天就开始探索GraphQL,使用像Spring Boot和graphql-java这样的工具,在您的下一个项目中释放其全部潜力。

源代码

您可以在Github上找到本教程的完整源代码。

Source:
https://dzone.com/articles/design-scalable-java-apis-with-graphql