此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring GraphQL 1.3.3spring-doc.cadn.net.cn

客户端

Spring for GraphQL 包括对通过 HTTP 执行 GraphQL 请求的客户端支持, WebSocket 和 RSocket 的 Socket 的 Socket 和 RSocket 的 Socket 的 Socketspring-doc.cadn.net.cn

GraphQlClient

GraphQlClient是一个合约,它声明了 GraphQL 请求的常见工作流程,即 独立于底层传输。这意味着请求使用相同的 API 执行 无论底层传输是什么,以及任何特定于传输的内容都是在 构建时间。spring-doc.cadn.net.cn

要创建GraphQlClient您需要以下扩展之一:spring-doc.cadn.net.cn

每个 API 都定义了一个Builder以及与运输相关的选项。所有构建器都扩展了 来自通用的基 GraphQlClientBuilder有选项 与所有扩展相关。spring-doc.cadn.net.cn

一旦你有了GraphQlClient您可以开始提出请求spring-doc.cadn.net.cn

HTTP 协议

HttpGraphQlClient使用 WebClient 执行 通过 HTTP 的 GraphQL 请求。spring-doc.cadn.net.cn

WebClient webClient = ... ;
HttpGraphQlClient graphQlClient = HttpGraphQlClient.create(webClient);

一次HttpGraphQlClient创建后,您可以开始使用相同的 API 执行请求,独立于底层 运输。如果需要更改任何特定于传输的详细信息,请使用mutate()在 现存HttpGraphQlClient要创建具有自定义设置的新实例:spring-doc.cadn.net.cn

   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 构建的,你可以按如下方式创建它:spring-doc.cadn.net.cn

String url = "wss://localhost:8080/graphql";
WebSocketClient client = new ReactorNettyWebSocketClient();

WebSocketGraphQlClient graphQlClient = WebSocketGraphQlClient.builder(url, client).build();

HttpGraphQlClientWebSocketGraphQlClient是面向连接的, 这意味着它需要在发出任何请求之前建立连接。开始时 要发出请求,将透明地建立连接。或者,使用 客户的start()方法在任何请求之前显式建立连接。spring-doc.cadn.net.cn

除了以连接为导向之外,WebSocketGraphQlClient也是多路复用的。 它为所有请求维护一个共享连接。如果连接丢失, 它会在下一个请求中重新建立,或者如果start()再次调用。您还可以 使用客户端的stop()方法取消正在进行的请求,关闭 connection 并拒绝新请求。spring-doc.cadn.net.cn

使用单个WebSocketGraphQlClientinstance 中,以便有一个 单个共享连接,用于对该服务器的所有请求。每个客户端实例 建立自己的连接,这通常不是单个服务器的意图。

一次WebSocketGraphQlClient创建后,您可以开始使用相同的 API 执行请求,独立于底层 运输。如果需要更改任何特定于传输的详细信息,请使用mutate()在 现存WebSocketGraphQlClient要创建具有自定义设置的新实例:spring-doc.cadn.net.cn

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"在连接开始时。spring-doc.cadn.net.cn

对于特定于 WebSocket 传输的拦截,您可以创建一个WebSocketGraphQlClientInterceptor:spring-doc.cadn.net.cn

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
	}

}

上述拦截器注册为任何其他GraphQlClientInterceptor并使用它来拦截 GraphQL 请求,但请注意 最多可以是一个类型为WebSocketGraphQlClientInterceptor.spring-doc.cadn.net.cn

RSocket 系列

RSocketGraphQlClient使用 RSocketRequester 执行 GraphQL 请求而不是 RSocket 请求。spring-doc.cadn.net.cn

URI uri = URI.create("wss://localhost:8080/rsocket");
WebsocketClientTransport transport = WebsocketClientTransport.create(url);

RSocketGraphQlClient client = RSocketGraphQlClient.builder()
		.clientTransport(transport)
		.build();

HttpGraphQlClientRSocketGraphQlClient是面向连接的, 这意味着它需要在发出任何请求之前建立一个会话。开始时 要发出请求,会话将以透明方式建立。或者,使用 客户的start()方法在任何请求之前显式建立会话。spring-doc.cadn.net.cn

RSocketGraphQlClient也是多路复用的。它维护一个共享会话 所有请求。如果会话丢失,则会在下一个请求中重新建立会话,或者如果start()再次调用。您还可以使用客户端的stop()取消 in-progress 请求,关闭会话并拒绝新请求。spring-doc.cadn.net.cn

使用单个RSocketGraphQlClientinstance 中,以便有一个 单个共享会话,用于对该服务器的所有请求。每个客户端实例 建立自己的连接,这通常不是单个服务器的意图。

一次RSocketGraphQlClient创建后,您可以开始使用相同的 API 执行请求,独立于底层 运输。spring-doc.cadn.net.cn

架构工人

GraphQlClient定义父项Builder替换为 所有扩展的构建器。目前,它允许您配置:spring-doc.cadn.net.cn

请求

一旦你有了GraphQlClient,你可以开始通过 retrieve()execute() 执行请求,其中前者只是后者的快捷方式。spring-doc.cadn.net.cn

取回

下面检索和解码查询的数据:spring-doc.cadn.net.cn

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可以是文本或通过代码生成的 generated request 对象。您还可以在文件中定义文档,并使用 Document Source 按文件名重新指定它们。spring-doc.cadn.net.cn

该路径是相对于 “data” 键的,并使用简单的点 (“.”) 分隔表示法 对于具有列表元素的可选数组索引的嵌套字段,例如"project.name""project.releases[0].version".spring-doc.cadn.net.cn

解码可能导致FieldAccessException如果给定路径不存在,或者 field 值为null并出现错误。FieldAccessException提供对 response 和字段:spring-doc.cadn.net.cn

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方法并处理响应:spring-doc.cadn.net.cn

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,可以在局部变量中定义,或者 constant,或者它可能通过代码生成的请求对象生成。spring-doc.cadn.net.cn

您还可以创建带有扩展名的文档文件.graphql.gql"graphql-documents/"并按文件名引用它们。spring-doc.cadn.net.cn

例如,给定一个名为projectReleases.graphqlsrc/main/resources/graphql-documents,内容为:spring-doc.cadn.net.cn

src/main/resources/graphql-documents/projectReleases.graphql
query projectReleases($slug: ID!) {
	project(slug: $slug) {
		name
		releases {
			version
		}
	}
}

然后,您可以:spring-doc.cadn.net.cn

Mono<Project> projectMono = graphQlClient.documentName("projectReleases") (1)
		.variable("slug", "spring-framework") (2)
		.retrieve()
		.toEntity(Project.class);
1 从 “projectReleases.graphql” 加载文档
2 提供变量值。

IntelliJ 的“JS GraphQL”插件支持具有代码完成的 GraphQL 查询文件。spring-doc.cadn.net.cn

您可以使用GraphQlClient Builder 自定义DocumentSource用于按名称加载文档。spring-doc.cadn.net.cn

订阅请求

GraphQlClient可以通过支持它的传输执行订阅。只 WebSocket 和 RSocket 传输支持 GraphQL 订阅,因此您需要 创建 WebSocketGraphQlClientRSocketGraphQlClientspring-doc.cadn.net.cn

取回

要启动订阅流,请使用retrieveSubscription这类似于单个响应的 retrieve ,但返回一个 响应,每个响应都解码为一些数据:spring-doc.cadn.net.cn

Flux<String> greetingFlux = client.document("subscription { greetings }")
		.retrieveSubscription("greeting")
		.toEntity(String.class);

Flux可以终止于SubscriptionErrorException如果订阅结束时间 服务器端显示 “error” 消息。异常提供对 GraphQL 错误的访问 从 “error” 消息解码。spring-doc.cadn.net.cn

Flux可能终止GraphQlTransportExceptionWebSocketDisconnectedException如果基础连接已关闭或丢失。在那个 case 中,您可以使用retryoperator 重新启动订阅。spring-doc.cadn.net.cn

要从客户端结束订阅,Flux必须取消,然后 WebSocket 传输向服务器发送 “complete” 消息。如何取消Flux取决于它的使用方式。一些运算符(如taketimeout他们自己 取消Flux.如果您订阅了Flux替换为Subscriber,您可以获得 对Subscription并通过它取消。这onSubscribe运算符 提供对Subscription.spring-doc.cadn.net.cn

执行

Retrieve 只是从每个 响应映射。如需更多控制,请使用executeSubscription方法并处理每个 直接响应:spring-doc.cadn.net.cn

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要通过客户端拦截所有请求:spring-doc.cadn.net.cn

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 端构建器注册它:spring-doc.cadn.net.cn

URI url = ... ;
WebSocketClient client = ... ;

WebSocketGraphQlClient graphQlClient = WebSocketGraphQlClient.builder(url, client)
		.interceptor(new MyInterceptor())
		.build();