此版本仍在开发中,尚未被视为稳定版本。最新的稳定版本请使用 Spring GraphQL 1.3.1! |
此版本仍在开发中,尚未被视为稳定版本。最新的稳定版本请使用 Spring GraphQL 1.3.1! |
Spring for GraphQL 包括客户端对通过 HTTP 执行 GraphQL 请求的支持, WebSocket 和 RSocket。
GraphQlClient
GraphQlClient
是一个合约,它声明了 GraphQL 请求的通用工作流,即
独立于基础传输。这意味着请求是使用相同的 API 执行的
无论底层传输是什么,以及特定于传输的任何内容都配置在
构建时间。
若要创建扩展,需要以下扩展之一:GraphQlClient
每个定义一个与传输相关的选项。所有构建器扩展
来自带有选项的通用基本 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...
网络套接字
WebSocketGraphQlClient
通过共享 WebSocket 连接执行 GraphQL 请求。
它是使用 Spring WebFlux 中的 WebSocketClient 构建的,您可以按如下方式创建它:
String url = "wss://localhost:8080/graphql";
WebSocketClient client = new ReactorNettyWebSocketClient();
WebSocketGraphQlClient graphQlClient = WebSocketGraphQlClient.builder(url, client).build();
与 相反,是面向连接的,
这意味着它需要在发出任何请求之前建立连接。当你开始的时候
要发出请求,连接是透明的。或者,使用
客户端在任何请求之前显式建立连接的方法。HttpGraphQlClient
WebSocketGraphQlClient
start()
除了面向连接外,还具有多路复用功能。
它为所有请求维护一个单一的共享连接。如果连接丢失,
它将在下一个请求或再次调用时重新建立。您还可以
使用客户端的方法取消正在进行的请求,关闭
连接,并拒绝新请求。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 对 RSocket 请求执行 GraphQL 请求。
URI uri = URI.create("wss://localhost:8080/rsocket");
WebsocketClientTransport transport = WebsocketClientTransport.create(url);
RSocketGraphQlClient client = RSocketGraphQlClient.builder()
.clientTransport(transport)
.build();
与 相反,是面向连接的,
这意味着它需要在发出任何请求之前建立一个会话。当你开始的时候
为了提出请求,会话是透明地建立的。或者,使用
客户端在任何请求之前显式建立会话的方法。HttpGraphQlClient
RSocketGraphQlClient
start()
RSocketGraphQlClient
也是多路复用的。它维护一个共享会话
所有请求。如果会话丢失,则在下一个请求或再次调用时重新建立会话。您也可以使用客户端的取消方法
正在进行的请求,关闭会话,并拒绝新请求。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 | 对目标类型路径处的数据进行解码。 |
输入文档可以是文本,也可以是通过代码生成的
生成的请求对象。您还可以在文件中定义文档,并使用文档源按文件名重新指定文档。String
路径相对于“data”键,并使用简单的点 (“.”) 分隔表示法
对于具有列表元素可选数组索引的嵌套字段,例如 或。"project.name"
"project.releases[0].version"
如果给定路径不存在,则解码可能会导致
字段值为 和 有错误。 提供对
响应和字段: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 | 在给定路径上解码数据 |
文档源
请求的文档是可以在局部变量中定义的文档,或者
常量,也可以通过代码生成的请求对象来生成。String
您还可以在类路径上创建扩展名或以下的文档文件,并按文件名引用它们。.graphql
.gql
"graphql-documents/"
例如,给定一个名为 的文件,其中包含 的内容: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 查询文件。
您可以使用构建器自定义按名称加载文档。GraphQlClient
DocumentSource
1 | 要执行的操作。 |
2 | 响应映射中要解码的“data”键下的路径。 |
3 | 对目标类型路径处的数据进行解码。 |
1 | 响应没有数据,只有错误 |
2 | 具有关联错误的字段null |
3 | 字段设置为null DataFetcher |
4 | 在给定路径上解码数据 |
1 | 从“projectReleases.graphql”加载文档 |
2 | 提供变量值。 |
订阅请求
GraphQlClient
可以通过支持订阅的传输执行订阅。只
WebSocket 和 RSocket 传输支持 GraphQL 订阅,因此需要
创建 WebSocketGraphQlClient 或 RSocketGraphQlClient。
取回
若要启动订阅流,请使用 which 类似于检索单个响应,但返回
响应,每个响应都解码为一些数据:retrieveSubscription
Flux<String> greetingFlux = client.document("subscription { greetings }")
.retrieveSubscription("greeting")
.toEntity(String.class);
如果订阅从
服务器端显示“错误”消息。该异常提供对 GraphQL 错误的访问
从“错误”消息解码。Flux
SubscriptionErrorException
如果基础连接关闭或丢失,则可能会终止。在那
如果您可以使用 Operator 重新启动订阅。Flux
GraphQlTransportException
WebSocketDisconnectedException
retry
若要从客户端结束订阅,必须取消,然后依次取消
WebSocket 传输向服务器发送“完整”消息。如何取消取决于它的使用方式。一些运营商,例如 or 他们自己
取消 .如果你订阅了 with a ,你可以得到一个
引用并通过它取消。运营商还
提供对 .Flux
Flux
take
timeout
Flux
Flux
Subscriber
Subscription
onSubscribe
Subscription
执行
Retrieve 只是从每个路径中的单个路径解码的快捷方式
响应映射。为了获得更多控制,请使用该方法并处理每个
直接响应: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);
}
}
创建拦截器后,通过客户端构建器注册它:
URI url = ... ;
WebSocketClient client = ... ;
WebSocketGraphQlClient graphQlClient = WebSocketGraphQlClient.builder(url, client)
.interceptor(new MyInterceptor())
.build();