<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web-graphql</artifactId>
<version>5.0.12</version>
</dependency>
Vert.x Web GraphQL 服务端组件
Vert.x Web GraphQL 将 Vert.x Web 与知名的 GraphQL-Java 框架深度整合,赋予你构建高性能反应式 GraphQL 服务端的能力。
| 本手册为 Vert.x Web GraphQL 的参考指南。建议提前阅读并熟悉 GraphQL-Java 入门文档。 |
快速上手
在项目构建配置中引入依赖:
-
Maven(在
pom.xml中):
-
Gradle(在
build.gradle文件中):
compile 'io.vertx:vertx-web-graphql:5.0.12'
处理器装配与配置
HTTP 传输通道
创建 Vert.x Web Route 并挂载 GraphQLHandler:
GraphQL graphQL = setupGraphQLJava();
router.route("/graphql").handler(GraphQLHandler.create(graphQL));
|
|
该 Handler 默认同时响应 GET 与 POST 请求。你也可以将其限制为特定的 HTTP 方法:
GraphQL graphQL = setupGraphQLJava();
router.post("/graphql").handler(GraphQLHandler.create(graphQL));
GraphQLHandler 必须依赖 BodyHandler 才能正常读取 POST 请求体中的 GraphQL 查询报文。
|
批量查询请求 (Query batching)
查询批处理(Query Batching)允许客户端向 GraphQL 端点一次性发送一个包含多个查询的 JSON 数组,而非单个请求对象。
Vert.x Web GraphQL 完整支持该特性,默认处于关闭状态。若需开启,请配置 GraphQLHandlerOptions:
GraphQLHandlerOptions options = new GraphQLHandlerOptions()
.setRequestBatchingEnabled(true);
GraphQLHandler handler = GraphQLHandler.create(graphQL, options);
基于 WebSocket 的 GraphQL 长连接传输
Vert.x Web GraphQL 完全兼容官方标准 GraphQL over WebSocket 协议。
WebSocket 传输通道在需要使用 GraphQL Subscription(实时订阅推送)时尤为关键,同时也可用于承载普通的 Query 与 Mutation。
默认配置未锁定 Origin 标头。为防范跨站 WebSocket 劫持攻击(CSWSH),强烈建议配置 Origin 白名单属性严格校验来源。
|
挂载 WebSocket 处理器:
router.route("/graphql").handler(GraphQLWSHandler.create(graphQL));
|
客户端在建立长连接握手时会请求
|
若需要在同一个 URI(如 /graphql)下同时兼容 HTTP 与 WebSocket,必须确保在路由链中将 GraphQLWSHandler 挂载在 GraphQLHandler 之前:
router.route("/graphql")
.handler(GraphQLWSHandler.create(graphQL))
.handler(GraphQLHandler.create(graphQL));
订阅(Subscription)对应的 DataFetcher 必须返回 org.reactivestreams.Publisher 反应式流发布者实例。
|
内置 GraphiQL 可视化调试控制台
在开发与联调期间,在浏览器中通过可视化 IDE GraphiQL 直接编写并执行查询非常高效。
通过挂载 GraphiQLHandler 即可开箱启用:
GraphiQLHandlerOptions options = new GraphiQLHandlerOptions()
.setEnabled(true);
GraphiQLHandler handler = GraphiQLHandler.create(vertx, options);
router.route("/graphiql*").subRouter(handler.router());
随后在浏览器中打开 http://localhost:8080/graphiql/ 即可直接交互。
出于生产安全考量,GraphiQL 界面默认处于禁用状态。若要在生产环境使用需显式调用 setEnabled(true);在开发模式(VERTXWEB_ENVIRONMENT=dev)下系统会自动激活该工具。
|
数据获取器 (Data Fetching)
GraphQL-Java 的 API 天然契合反应式非阻塞模型:针对 Query 默认采用异步并行执行策略(针对 Mutation 采用异步串行策略)。
为了遵守 Vert.x 的黄金铁律(绝对不阻塞 EventLoop 线程),在编写 DataFetcher 时,只需返回 Java 的 CompletionStage 或 Vert.x 的 Future,而绝不要阻塞等待:
DataFetcher<CompletionStage<List<Link>>> dataFetcher = environment -> {
Future<List<Link>> future = retrieveLinksFromBackend(environment);
return future.toCompletionStage();
};
RuntimeWiring runtimeWiring = RuntimeWiring.newRuntimeWiring()
.type("Query", builder -> builder.dataFetcher("allLinks", dataFetcher))
.build();
|
为了避免在每个 DataFetcher 中手动将 Vert.x
配置后即可在 DataFetcher 中直接返回 Vert.x 的
|
在 DataFetcher 中获取当前请求上下文
在很多业务中,GraphQL 路由前面通常挂载了身份认证 Handler。DataFetcher 需要获知当前登录的用户是谁以收敛数据查询范围。
你可以直接从 DataFetchingEnvironment 的 GraphQL 上下文中提取 RoutingContext:
DataFetcher<CompletionStage<List<Link>>> dataFetcher = environment -> {
RoutingContext routingContext = environment.getGraphQlContext().get(RoutingContext.class);
UserContext user = routingContext.userContext();
Future<List<Link>> future = retrieveLinksPostedBy(user);
return future.toCompletionStage();
};
JSON 数据类型无缝适配
在 Vert.x 应用中,极高频地直接使用 JsonObject 与 JsonArray 表达数据。为了让 GraphQL-Java 能够原生透传读取 JsonObject 的属性字段,只需注册 JsonObjectAdapter 插桩即可:
graphQLBuilder.instrumentation(new JsonObjectAdapter());
批量加载器 (Batch loading / DataLoader)
DataLoader 能够通过批处理批量合并请求与缓存结果,彻底解决 GraphQL 著名的 N+1 查询性能问题。
首先创建批量加载器:
BatchLoaderWithContext<String, Link> linksBatchLoader = (ids, env) -> {
// 批量根据传入的多个 ID 一次性从数据库或底层服务返回一组 Links
return retrieveLinksFromBackend(ids, env);
};
随后在 beforeExecute 回调中为每次请求注册 DataLoader 即可:
GraphQLHandler handler = GraphQLHandler.builder(graphQL).beforeExecute(builderWithContext -> {
DataLoader<String, Link> linkDataLoader = DataLoaderFactory.newDataLoader(linksBatchLoader);
DataLoaderRegistry dataLoaderRegistry = new DataLoaderRegistry().register("link", linkDataLoader);
builderWithContext.builder().dataLoaderRegistry(dataLoaderRegistry);
}).build();
GraphQL Multipart 文件流式上传
遵循标准的 GraphQL Multipart Request 开放规范。开启后客户端可以在单个 GraphQL Mutation 变更中直接完成文件二进制上传。
只需在 options 中配置 setRequestMultipartEnabled(true) 并在路由上挂载 BodyHandler 即可:
GraphQLHandlerOptions options = new GraphQLHandlerOptions()
.setRequestMultipartEnabled(true);
GraphQLHandler graphQLHandler = GraphQLHandler.create(graphQL, options);
Router router = Router.router(vertx);
router.route().handler(BodyHandler.create());
router.route("/graphql").handler(graphQLHandler);
在 DataFetcher 内部通过 environment.getArgument("myFile") 获取 FileUpload 实例。