对于最新的稳定版本,请使用 Spring GraphQL 1.3.2! |
对于最新的稳定版本,请使用 Spring GraphQL 1.3.2! |
Spring for GraphQL 包括对通过 HTTP 执行 GraphQL 请求的客户端支持, WebSocket 和 RSocket 的 Socket 的 Socket 和 RSocket 的 Socket 的 Socket
GraphQlClient
GraphQlClient
是一个合约,它声明了 GraphQL 请求的常见工作流程,即
独立于底层传输。这意味着请求使用相同的 API 执行
无论底层传输是什么,以及任何特定于传输的内容都是在
构建时间。
要创建 ,您需要以下扩展之一:GraphQlClient
每个 define a 都包含与传输相关的选项。所有构建器都扩展了
来自一个常见的、基本的 GraphQlClient Builder
选项。
与所有扩展相关。Builder
一旦你有了,你就可以开始提出请求了。GraphQlClient
HTTP 协议
HttpGraphQlClient
使用 WebClient 执行
通过 HTTP 的 GraphQL 请求。
WebClient webClient = ... ;
HttpGraphQlClient graphQlClient = HttpGraphQlClient.create(webClient);
创建后,您可以开始使用相同的 API 执行请求,独立于底层
运输。如果您需要更改任何特定于传输的详细信息,请在
existing 创建具有自定义设置的新实例:HttpGraphQlClient
mutate()
HttpGraphQlClient
WebClient webClient = ... ;
HttpGraphQlClient graphQlClient = HttpGraphQlClient.builder(webClient)
.headers(headers -> headers.setBasicAuth("joe", "..."))
.build();
// Perform requests with graphQlClient...
HttpGraphQlClient anotherGraphQlClient = graphQlClient.mutate()
.headers(headers -> headers.setBasicAuth("peter", "..."))
.build();
// Perform requests with anotherGraphQlClient...
WebSocket 浏览器
WebSocketGraphQlClient
通过共享 WebSocket 连接执行 GraphQL 请求。
它是使用 Spring WebFlux 的 WebSocketClient 构建的,你可以按如下方式创建它:
String url = "wss://localhost:8080/graphql";
WebSocketClient client = new ReactorNettyWebSocketClient();
WebSocketGraphQlClient graphQlClient = WebSocketGraphQlClient.builder(url, client).build();
与 相比,它是面向连接的,
这意味着它需要在发出任何请求之前建立连接。开始时
要发出请求,将透明地建立连接。或者,使用
client's 方法在任何请求之前显式建立连接。HttpGraphQlClient
WebSocketGraphQlClient
start()
除了面向连接之外,还进行了多路复用。
它为所有请求维护一个共享连接。如果连接丢失,
它会在下一个请求或 if 再次调用时重新建立。您还可以
使用客户端的方法取消正在进行的请求,关闭
connection 并拒绝新请求。WebSocketGraphQlClient
start()
stop()
为每个服务器使用单个实例,以便获得
单个共享连接,用于对该服务器的所有请求。每个客户端实例
建立自己的连接,这通常不是单个服务器的意图。WebSocketGraphQlClient |
创建后,您可以开始使用相同的 API 执行请求,独立于底层
运输。如果您需要更改任何特定于传输的详细信息,请在
existing 创建具有自定义设置的新实例:WebSocketGraphQlClient
mutate()
WebSocketGraphQlClient
URI url = ... ;
WebSocketClient client = ... ;
WebSocketGraphQlClient graphQlClient = WebSocketGraphQlClient.builder(url, client)
.headers(headers -> headers.setBasicAuth("joe", "..."))
.build();
// Use graphQlClient...
WebSocketGraphQlClient anotherGraphQlClient = graphQlClient.mutate()
.headers(headers -> headers.setBasicAuth("peter", "..."))
.build();
// Use anotherGraphQlClient...
拦截 器
GraphQL over WebSocket 协议除了定义许多面向连接的消息外,还执行
请求。例如,客户端发送,服务器在连接开始时响应。"connection_init"
"connection_ack"
对于特定于 WebSocket 传输的拦截,您可以创建一个:WebSocketGraphQlClientInterceptor
static class MyInterceptor implements WebSocketGraphQlClientInterceptor {
@Override
public Mono<Object> connectionInitPayload() {
// ... the "connection_init" payload to send
}
@Override
public Mono<Void> handleConnectionAck(Map<String, Object> ackPayload) {
// ... the "connection_ack" payload received
}
}
将上述拦截器注册为任何其他拦截器,并使用它来拦截 GraphQL 请求,但请注意
最多可以是一个类型为 的拦截器 。GraphQlClientInterceptor
WebSocketGraphQlClientInterceptor
RSocket 系列
RSocketGraphQlClient
使用 RSocketRequester 执行 GraphQL 请求而不是 RSocket 请求。
URI uri = URI.create("wss://localhost:8080/rsocket");
WebsocketClientTransport transport = WebsocketClientTransport.create(url);
RSocketGraphQlClient client = RSocketGraphQlClient.builder()
.clientTransport(transport)
.build();
与 相比,它是面向连接的,
这意味着它需要在发出任何请求之前建立一个会话。开始时
要发出请求,会话将以透明方式建立。或者,使用
client's 方法显式建立会话。HttpGraphQlClient
RSocketGraphQlClient
start()
RSocketGraphQlClient
也是多路复用的。它维护一个共享会话
所有请求。如果会话丢失,则会在下一个请求或再次调用时重新建立会话。您还可以使用 client's 方法,该方法将
in-progress 请求,关闭会话并拒绝新请求。start()
stop()
为每个服务器使用单个实例,以便获得
单个共享会话,用于对该服务器的所有请求。每个客户端实例
建立自己的连接,这通常不是单个服务器的意图。RSocketGraphQlClient |
创建后,您可以开始使用相同的 API 执行请求,独立于底层
运输。RSocketGraphQlClient
为每个服务器使用单个实例,以便获得
单个共享连接,用于对该服务器的所有请求。每个客户端实例
建立自己的连接,这通常不是单个服务器的意图。WebSocketGraphQlClient |
为每个服务器使用单个实例,以便获得
单个共享会话,用于对该服务器的所有请求。每个客户端实例
建立自己的连接,这通常不是单个服务器的意图。RSocketGraphQlClient |
请求
一旦你有了 GraphQlClient
,你就可以开始通过 retrieve() 或 execute() 执行请求,其中前者只是后者的快捷方式。
取回
下面检索和解码查询的数据:
String document = "{" +
" project(slug:\"spring-framework\") {" +
" name" +
" releases {" +
" version" +
" }"+
" }" +
"}";
Mono<Project> projectMono = graphQlClient.document(document) (1)
.retrieve("project") (2)
.toEntity(Project.class); (3)
1 | 要执行的操作。 |
2 | 响应映射中要从中解码的 “data” 键下的路径。 |
3 | 解码目标类型的路径中的数据。 |
输入文档可以是文本或通过代码生成的
generated request 对象。您还可以在文件中定义文档,并使用 Document Source 按文件名重新指定它们。String
该路径是相对于 “data” 键的,并使用简单的点 (“.”) 分隔表示法
对于具有列表元素的可选数组索引的嵌套字段,例如 或。"project.name"
"project.releases[0].version"
如果给定路径不存在,或者
field 值为 和 有错误。 提供对
response 和字段:FieldAccessException
null
FieldAccessException
Mono<Project> projectMono = graphQlClient.document(document)
.retrieve("project")
.toEntity(Project.class)
.onErrorResume(FieldAccessException.class, ex -> {
ClientGraphQlResponse response = ex.getResponse();
// ...
ClientResponseField field = ex.getField();
// ...
});
执行
Retrieve 只是从
响应映射。如需更多控制,请使用该方法并处理响应:execute
例如:
Mono<Project> projectMono = graphQlClient.document(document)
.execute()
.map(response -> {
if (!response.isValid()) {
// Request failure... (1)
}
ClientResponseField field = response.field("project");
if (!field.hasValue()) {
if (field.getError() != null) {
// Field failure... (2)
}
else {
// Optional field set to null... (3)
}
}
return field.toEntity(Project.class); (4)
});
1 | 响应没有数据,只有错误 |
2 | 字段是 和 具有关联错误null |
3 | 字段,该字段由其null DataFetcher |
4 | 解码给定路径上的数据 |
文档源
请求的文档是可以在局部变量中定义的 a,或者
constant,或者它可能通过代码生成的请求对象生成。String
您还可以在类路径中创建带有扩展名或 under 的文档文件,并通过文件名引用它们。.graphql
.gql
"graphql-documents/"
例如,给定一个名为 in 的文件,其中包含内容:projectReleases.graphql
src/main/resources/graphql-documents
query projectReleases($slug: ID!) {
project(slug: $slug) {
name
releases {
version
}
}
}
然后,您可以:
Mono<Project> projectMono = graphQlClient.documentName("projectReleases") (1)
.variable("slug", "spring-framework") (2)
.retrieve()
.toEntity(Project.class);
1 | 从 “projectReleases.graphql” 加载文档 |
2 | 提供变量值。 |
IntelliJ 的“JS GraphQL”插件支持具有代码完成的 GraphQL 查询文件。
您可以使用 Builder 自定义 以按名称加载文档。GraphQlClient
DocumentSource
1 | 要执行的操作。 |
2 | 响应映射中要从中解码的 “data” 键下的路径。 |
3 | 解码目标类型的路径中的数据。 |
1 | 响应没有数据,只有错误 |
2 | 字段是 和 具有关联错误null |
3 | 字段,该字段由其null DataFetcher |
4 | 解码给定路径上的数据 |
1 | 从 “projectReleases.graphql” 加载文档 |
2 | 提供变量值。 |
订阅请求
GraphQlClient
可以通过支持它的传输执行订阅。只
WebSocket 和 RSocket 传输支持 GraphQL 订阅,因此您需要
创建 WebSocketGraphQlClient 或 RSocketGraphQlClient。
取回
要启动订阅流,请使用 which 类似于 retrieve 来获取单个响应,但返回
响应,每个响应都解码为一些数据:retrieveSubscription
Flux<String> greetingFlux = client.document("subscription { greetings }")
.retrieveSubscription("greeting")
.toEntity(String.class);
如果订阅从
服务器端显示 “error” 消息。异常提供对 GraphQL 错误的访问
从 “error” 消息解码。Flux
SubscriptionErrorException
如果底层连接已关闭或丢失,则可能会终止。在那个
的情况下,您可以使用 Operator 重新启动订阅。Flux
GraphQlTransportException
WebSocketDisconnectedException
retry
要从客户端结束订阅,必须取消 ,然后
WebSocket 传输向服务器发送 “complete” 消息。如何取消 取决于它的使用方式。一些运算符,例如 or 自己
取消 .如果您使用 订阅 ,则可以获得
引用 and cancel 通过它。操作员还
提供对 的访问。Flux
Flux
take
timeout
Flux
Flux
Subscriber
Subscription
onSubscribe
Subscription
执行
Retrieve 只是从每个
响应映射。要获得更多控制,请使用 method 并处理每个
直接响应:executeSubscription
Flux<String> greetingFlux = client.document("subscription { greetings }")
.executeSubscription()
.map(response -> {
if (!response.isValid()) {
// Request failure...
}
ClientResponseField field = response.field("project");
if (!field.hasValue()) {
if (field.getError() != null) {
// Field failure...
}
else {
// Optional field set to null... (3)
}
}
return field.toEntity(String.class)
});
拦截
您创建一个 以通过客户端拦截所有请求:GraphQlClientInterceptor
static class MyInterceptor implements GraphQlClientInterceptor {
@Override
public Mono<ClientGraphQlResponse> intercept(ClientGraphQlRequest request, Chain chain) {
// ...
return chain.next(request);
}
@Override
public Flux<ClientGraphQlResponse> interceptSubscription(ClientGraphQlRequest request, SubscriptionChain chain) {
// ...
return chain.next(request);
}
}
创建拦截器后,通过 Client 端构建器注册它:
URI url = ... ;
WebSocketClient client = ... ;
WebSocketGraphQlClient graphQlClient = WebSocketGraphQlClient.builder(url, client)
.interceptor(new MyInterceptor())
.build();