HTTP 与 Web 开发

构建 GraphQL 服务端应用

本指南将向你展示如何使用 Vert.x Web GraphQL 模块快速搭建高性能 GraphQL 数据查询与变更服务。

你将构建什么

你将构建一个 GraphQL 服务端,用于管理个人待办事项任务(Todo List)。

该应用程序由以下几个核心文件组成:

  1. tasks.graphqls:GraphQL Schema 契约定义文件;

  2. Task:数据实体 POJO 类;

  3. GraphQLVerticle:驱动服务的 Vert.x Verticle。

前置要求

  • 文本编辑器或 IDE

  • Java 17 或更高版本

  • Maven 或 Gradle

创建工程项目

本项目代码提供了 Maven 与 Gradle 两种构建方式,二者完全等价。

使用 Maven

以下是推荐的 pom.xml 构建配置:

使用 Gradle

若使用带有 Kotlin DSL 的 Gradle,对应的 build.gradle.kts 文件如下:

使用 Vert.x Web 与 GraphQL 管理待办事项

定义 GraphQL Schema 契约

首先,我们需要在资源目录中定义待办应用的 GraphQL Schema:

GraphQL Schema src/main/resources/tasks.graphqls
type Task {
  id: String
  description: String
  completed: Boolean
}

type Query {
  allTasks(uncompletedOnly: Boolean = true): [Task]
}

type Mutation {
  complete(id: String!): Boolean
}

该 Schema 定义了:

  • Task 类型:包含 id、description(描述)与 completed(是否已完成)三个字段;

  • allTasks 查询(Query):返回任务列表,支持传入可选的 uncompletedOnly 参数(默认值为 true,即仅查询未完成事项);

  • complete 变更(Mutation):接收任务的 id 作为参数,并返回布尔值表示该任务标记完成是否成功。

编写服务端核心逻辑

在应用层,待办任务由 Task 类进行映射:

1 创建 Task 实例时自动为其生成并分配随机唯一标识。
Task 类中的字段名称必须与 GraphQL Schema 中声明的字段名称严格保持一致。

在应用启动时,我们预置几条初始任务数据:

随后,我们需要配置并组装 GraphQL-Java 引擎:

1 从 Classpath 读取并解析 tasks.graphqls 模式文件;
2 TypeDefinitionRegistry 是 GraphQL-Java 在运行期对 Schema 模式定义的内存表示;
3 RuntimeWiring 告诉 GraphQL-Java 如何解析具体的数据类型并关联数据拉取器(DataFetcher);
4 GraphQLSchema 将运行期类型定义与具体的数据解析器深度绑定连接;
5 最终实例化应用程序的 GraphQL 核心引擎。

那么,如何实现一个数据拉取器(DataFetcher)呢?

allTasks 数据拉取器从 DataFetchingEnvironment 上下文中获取客户端传入的 uncompletedOnly 参数。如果客户端未传,则采用 Schema 中预设的默认值 true。

切勿在数据拉取器中阻塞 Vert.x Event Loop 事件循环! 在本实战指南中,数据集规模极小且直接驻留内存,因此同步实现 allTasks 是安全的。但在生产环境中与数据库、缓存或第三方 Web 服务交互时,请务必确保你的 DataFetcher 返回异步的 CompletionStage 或 Vert.x Future。详情请参阅 Vert.x Web GraphQL Handler 官方手册。

complete 数据变更的实现逻辑与此类似:

它从客户端提取参数中的任务 id,检索匹配的任务并将其状态置为已完成,最后返回 true 告知调用方操作成功。

大功告成!现在我们在 Verticle 的 start 方法中将所有组件装配在一起:

1 为 GraphQL-Java 实例创建对应的 Vert.x Web GraphQLHandler 处理器;
2 声明一个全匹配路由并挂载 BodyHandler(处理 HTTP POST 请求正文所必需);
3 为 /graphql 路径定义专属路由,并将 GraphQL 处理器挂载就位。

运行与实测

运行该应用非常直观:

  • 直接在 IDE 中运行 GraphQLVerticle.java 中的 main 方法;

  • 或者通过 Maven 运行:mvn compile exec:java;

  • 或者通过 Gradle 运行:./gradlew run。

以下示例使用流行的命令行 HTTP 客户端 HTTPie 进行测试演示:

1. 查询所有未完成的待办任务

打开终端并执行 GraphQL 查询:

http :8080/graphql query='
query {
  allTasks {
    id,
    description
  }
}'

你将看到结构化 JSON 响应:

{
    "data": {
        "allTasks": [
            {
                "description": "Learn GraphQL",
                "id": "4a9f53fd-584f-4169-b725-6b320043db8b"
            },
            {
                "description": "Profit",
                "id": "03770db5-a8ad-44b3-ad6e-6fe979015088"
            },
            {
                "description": "Build awesome GraphQL server",
                "id": "6b000f72-8aa9-4f4e-9539-5da2ab11cd94"
            }
        ]
    }
}

2. 标记完成一条任务

将 Learn GraphQL 任务标记为完成:

http :8080/graphql query='
mutation {
  complete(id: "4a9f53fd-584f-4169-b725-6b320043db8b")
}'
请将上述查询中的 id 替换为你实际查询返回的真实 ID。

执行后将返回:

{
    "data": {
        "complete": true
    }
}

3. 检索全量待办任务(含已完成)

将 uncompletedOnly 参数指定为 false:

http :8080/graphql query='
query {
  allTasks(uncompletedOnly: false) {
    id
    description
    completed
  }
}'

你将看到包含已完成状态("completed": true)的完整任务集合。

本文总结

通过本指南,我们掌握了:

  1. Vert.x Web 与 GraphQL-Java 的桥接集成流程;

  2. 定义清晰的 GraphQL Schema 类型体系;

  3. 实现非阻塞的 Query 查询与 Mutation 变更拉取器。