<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web-graphql</artifactId>
<version>5.0.1</version>
</dependency>
Vert.x Web GraphQL
Vert.x Web GraphQL 扩展了 Vert.x Web,集成了 GraphQL-Java 库,以便您能够构建 GraphQL 服务器。
这是 Vert.x Web GraphQL 的参考文档。强烈建议您首先熟悉 GraphQL-Java API。您可以先阅读 GraphQL-Java 文档。 |
快速入门
要使用此模块,请将以下内容添加到您的 Maven POM 文件的 依赖项 部分
或者,如果您使用 Gradle
compile 'io.vertx:vertx-web-graphql:5.0.1'
处理器设置
HTTP
为此创建一个 Vert.x Web Route
和一个 GraphQLHandler
GraphQL graphQL = setupGraphQLJava();
router.route("/graphql").handler(GraphQLHandler.create(graphQL));
|
该处理器同时服务于 GET
和 POST
请求。但是,您可以将服务限制为一种 HTTP 方法类型
GraphQL graphQL = setupGraphQLJava();
router.post("/graphql").handler(GraphQLHandler.create(graphQL));
GraphQLHandler 需要一个 BodyHandler 来读取 POST 请求内容。 |
查询批处理
查询批处理是指向 GraphQL 端点发布一个数组而不是单个对象。
Vert.x Web GraphQL 可以处理此类请求,但此功能默认禁用。要启用此功能,请创建带选项的 GraphQLHandler
GraphQLHandlerOptions options = new GraphQLHandlerOptions()
.setRequestBatchingEnabled(true);
GraphQLHandler handler = GraphQLHandler.create(graphQL, options);
基于 WebSocket 的 GraphQL
Vert.x Web GraphQL 与 GraphQL over Websocket 协议兼容。
WebSocket 传输在您需要向 GraphQL 模式添加订阅时特别有用,但您也可以将其用于查询和变更。
默认情况下,配置不包含默认的 Origin 属性。为防止来自 Web 浏览器的跨站 WebSocket 劫持攻击,建议将此属性设置为应用程序面向互联网的源。这将强制检查 WebSocket 源是否来自此应用程序。此检查很重要,因为 WebSockets 不受同源策略的限制,攻击者可以轻易地从恶意网页发起针对 GraphQL WS 处理器 ws:// 或 wss:// 端点 URL 的 WebSocket 请求。 |
router.route("/graphql").handler(GraphQLWSHandler.create(graphQL));
客户端将请求 |
|
为了在同一 URI 上同时支持 HTTP 和 WebSockets,必须在 GraphQLHandler
之前将 GraphQLWSHandler
安装到 Router
router.route("/graphql")
.handler(GraphQLWSHandler.create(graphQL))
.handler(GraphQLHandler.create(graphQL));
一个 订阅 DataFetcher 必须返回一个 org.reactivestreams.Publisher 实例。 |
GraphiQL IDE
在您构建应用程序时,在 GraphiQL 中测试 GraphQL 查询会很方便。
为此,为 GraphiQL 资源创建一个路由,并为它们创建一个 GraphiQLHandler
GraphiQLHandlerOptions options = new GraphiQLHandlerOptions()
.setEnabled(true);
GraphiQLHandler handler = GraphiQLHandler.create(vertx, options);
router.route("/graphiql*").subRouter(handler.router());
然后浏览到 https://:8080/graphiql/。
出于安全原因,GraphiQL 用户界面默认是禁用的。这就是为什么您必须配置 GraphiQLHandlerOptions 来启用它。 |
当 Vert.x Web 在开发模式下运行时,GraphiQL 会自动启用。要开启开发模式,请使用 |
如果您的应用程序受身份验证保护,您可以动态自定义 GraphiQL 发送的请求头
GraphiQLHandlerOptions options = new GraphiQLHandlerOptions()
.setEnabled(true);
GraphiQLHandler handler = GraphiQLHandler.builder(vertx)
.with(options)
.addingHeaders(rc -> {
String token = rc.get("token");
return MultiMap.caseInsensitiveMultiMap().add("Authorization", "Bearer " + token);
})
.build();
router.route("/graphiql*").subRouter(handler.router());
请参阅 GraphiQLHandlerOptions
文档以获取更多详细信息。
数据获取
GraphQL-Java API 非常适合异步世界:异步执行策略是查询的默认策略(变更的默认策略是串行异步)。
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();
无需在每个数据获取器实现中手动将 Vert.x 首先,在配置 GraphQL-Java 时声明该插装。 这样您就可以直接返回 Vert.x Future。 |
为数据获取器提供上下文
通常,GraphQLHandler
或 GraphQLWSHandler
将在其他路由处理器之后声明。例如,您可以使用身份验证来保护您的应用程序。
在这种情况下,您的数据获取器可能需要知道哪个用户已登录,以便缩小结果范围。
为此,您可以通过检查 DataFetchingEnvironment
来检索 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 数据结果
默认的 GraphQL 数据获取器是 PropertyDataFetcher
。它无需进一步配置即可读取领域对象的字段。
然而,在 Vert.x 应用程序中,通常会使用 JsonArray
和 JsonObject
。PropertyDataFetcher
可以直接读取 JsonArray
中的项目,但不能读取 JsonObject
的字段。
这个问题的解决方案取决于您的 GraphQL-Java 版本。
两种解决方案都允许您混合使用 JsonObject 、JsonArray 和领域对象的结果。 |
GraphQL-Java 20 及更高版本
使用 JsonObjectAdapter
插装 来配置 GraphQL-Java。
graphQLBuilder.instrumentation(new JsonObjectAdapter());
批量加载
DataLoaders 通过批处理获取请求和缓存结果来帮助您高效地加载数据。
首先,创建一个批量加载器
BatchLoaderWithContext<String, Link> linksBatchLoader = (ids, env) -> {
// retrieveLinksFromBackend takes a list of ids and returns a CompletionStage for a list of links
return retrieveLinksFromBackend(ids, env);
};
然后,配置 GraphQLHandler
以便为每个请求创建 DataLoaderRegistry
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 多部分请求 是一种可互操作的多部分表单字段结构,用于 GraphQL
请求。通过启用此功能,GraphQL 客户端将能够使用单个变更调用上传文件。所有服务器端文件处理都将由 GraphQLHandler
抽象。
要启用此功能,请创建一个 GraphQLHandler
,将其 requestMultipartEnabled
配置设置为 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);
如果路由器没有 BodyHandler ,多部分请求解析器将无法处理 GraphQL 变更调用。 |
最后,创建 Upload
标量,并将其设置到 RuntimeWiring
RuntimeWiring runtimeWiring = RuntimeWiring.newRuntimeWiring().scalar(UploadScalar.build()).build();
FileUpload
实例可以通过使用 DataFetchingEnvironment::getArgument
方法来访问。
FileUpload file = environment.getArgument("myFile");