Polishing
See gh-771
This commit is contained in:
@@ -99,8 +99,8 @@ public abstract class AbstractGraphQlClientBuilder<B extends AbstractGraphQlClie
|
||||
}
|
||||
|
||||
@Override
|
||||
public B documentSource(DocumentSource contentLoader) {
|
||||
this.documentSource = contentLoader;
|
||||
public B documentSource(DocumentSource documentSource) {
|
||||
this.documentSource = documentSource;
|
||||
return self();
|
||||
}
|
||||
|
||||
@@ -195,8 +195,7 @@ public abstract class AbstractGraphQlClientBuilder<B extends AbstractGraphQlClie
|
||||
|
||||
private Chain createExecuteChain(GraphQlTransport transport) {
|
||||
|
||||
Chain chain = request -> transport
|
||||
.execute(request)
|
||||
Chain chain = request -> transport.execute(request)
|
||||
.map(response -> new DefaultClientGraphQlResponse(request, response, getEncoder(), getDecoder()));
|
||||
|
||||
return this.interceptors.stream()
|
||||
|
||||
@@ -100,8 +100,8 @@ public abstract class AbstractGraphQlClientSyncBuilder<B extends AbstractGraphQl
|
||||
}
|
||||
|
||||
@Override
|
||||
public B documentSource(DocumentSource contentLoader) {
|
||||
this.documentSource = contentLoader;
|
||||
public B documentSource(DocumentSource documentSource) {
|
||||
this.documentSource = documentSource;
|
||||
return self();
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ final class DefaultGraphQlClient implements GraphQlClient {
|
||||
|
||||
private final GraphQlClientInterceptor.Chain nonBlockingChain;
|
||||
|
||||
private final GraphQlClientInterceptor.SubscriptionChain executeSubscriptionChain;
|
||||
private final GraphQlClientInterceptor.SubscriptionChain subscriptionChain;
|
||||
|
||||
@Nullable
|
||||
private final Duration blockingTimeout;
|
||||
@@ -63,7 +63,7 @@ final class DefaultGraphQlClient implements GraphQlClient {
|
||||
this.documentSource = documentSource;
|
||||
this.blockingChain = blockingChain;
|
||||
this.nonBlockingChain = adaptToNonBlockingChain(blockingChain, scheduler);
|
||||
this.executeSubscriptionChain = request -> Flux.error(new IllegalStateException("Subscriptions on supported"));
|
||||
this.subscriptionChain = request -> Flux.error(new IllegalStateException("Subscriptions on supported"));
|
||||
this.blockingTimeout = blockingTimeout;
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ final class DefaultGraphQlClient implements GraphQlClient {
|
||||
this.documentSource = documentSource;
|
||||
this.blockingChain = adaptToBlockingChain(nonBlockingChain, blockingTimeout);
|
||||
this.nonBlockingChain = nonBlockingChain;
|
||||
this.executeSubscriptionChain = subscriptionChain;
|
||||
this.subscriptionChain = subscriptionChain;
|
||||
this.blockingTimeout = blockingTimeout;
|
||||
}
|
||||
|
||||
@@ -217,7 +217,7 @@ final class DefaultGraphQlClient implements GraphQlClient {
|
||||
|
||||
@Override
|
||||
public Flux<ClientGraphQlResponse> executeSubscription() {
|
||||
return initRequest().flatMapMany(request -> executeSubscriptionChain.next(request)
|
||||
return initRequest().flatMapMany(request -> subscriptionChain.next(request)
|
||||
.onErrorResume(
|
||||
ex -> !(ex instanceof GraphQlClientException),
|
||||
ex -> Mono.error(new GraphQlTransportException(ex, request))));
|
||||
|
||||
@@ -111,15 +111,15 @@ final class DefaultSyncHttpGraphQlClientBuilder
|
||||
});
|
||||
|
||||
RestClient restClient = this.restClientBuilder.build();
|
||||
HttpSyncGraphQlTransport syncTransport = new HttpSyncGraphQlTransport(restClient);
|
||||
HttpSyncGraphQlTransport transport = new HttpSyncGraphQlTransport(restClient);
|
||||
|
||||
GraphQlClient graphQlClient = super.buildGraphQlClient(syncTransport);
|
||||
GraphQlClient graphQlClient = super.buildGraphQlClient(transport);
|
||||
return new DefaultHttpSyncGraphQlClient(graphQlClient, restClient, getBuilderInitializer());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Default {@link HttpGraphQlClient} implementation.
|
||||
* Default {@link HttpSyncGraphQlClient} implementation.
|
||||
*/
|
||||
private static class DefaultHttpSyncGraphQlClient
|
||||
extends AbstractDelegatingGraphQlClient implements HttpSyncGraphQlClient {
|
||||
|
||||
@@ -89,14 +89,14 @@ public interface GraphQlClient {
|
||||
|
||||
|
||||
/**
|
||||
* Base builder to create a {@link GraphQlClient}.
|
||||
* Base builder for creating and initializing a {@link GraphQlClient}.
|
||||
* @since 1.3
|
||||
*/
|
||||
interface BaseBuilder<B extends BaseBuilder<B>> {
|
||||
|
||||
/**
|
||||
* Configure a {@link DocumentSource} for use with
|
||||
* {@link #documentName(String)} for resolving a document by name.
|
||||
* Configure a {@link DocumentSource} strategy to resolve a document by
|
||||
* name. For use within {@link #documentName(String)}.
|
||||
* <p>By default, this is set to {@link ResourceDocumentSource} with
|
||||
* classpath location {@code "graphql-documents/"} and
|
||||
* {@link ResourceDocumentSource#FILE_EXTENSIONS} as extensions.
|
||||
@@ -107,8 +107,9 @@ public interface GraphQlClient {
|
||||
* Configure a timeout to use for blocking execution.
|
||||
* <p>By default this is not set, in which case the behavior depends on
|
||||
* connection and request timeout settings of the underlying transport.
|
||||
* We recommend configuring timeout values directly on the underlying
|
||||
* transport, which provides more control over such settings.
|
||||
* We recommend configuring timeout values directly if possible on the
|
||||
* underlying transport library such an HTTP client library as that can
|
||||
* provide more control over such settings.
|
||||
* @param blockingTimeout the timeout to use
|
||||
*/
|
||||
B blockingTimeout(@Nullable Duration blockingTimeout);
|
||||
@@ -123,7 +124,7 @@ public interface GraphQlClient {
|
||||
|
||||
/**
|
||||
* Builder to create a {@link GraphQlClient} instance with a
|
||||
* synchronous transport and interceptors.
|
||||
* synchronous execution chain and transport.
|
||||
* @since 1.3
|
||||
* @see SyncGraphQlTransport
|
||||
*/
|
||||
@@ -156,8 +157,8 @@ public interface GraphQlClient {
|
||||
|
||||
|
||||
/**
|
||||
* Builder to create {@link GraphQlClient} instances with a non-blocking
|
||||
* {@link GraphQlTransport} and interceptors.
|
||||
* Builder to create a {@link GraphQlClient} with a non-blocking execution
|
||||
* chain and transport.
|
||||
*/
|
||||
interface Builder<B extends Builder<B>> extends BaseBuilder<B> {
|
||||
|
||||
@@ -242,10 +243,10 @@ public interface GraphQlClient {
|
||||
RequestSpec attributes(Consumer<Map<String, Object>> attributesConsumer);
|
||||
|
||||
/**
|
||||
* Shortcut for {@link #execute()} with a field path to decode from.
|
||||
* <p>If you want to decode the full data instead, use {@link #execute()}:
|
||||
* Shortcut for {@link #executeSync()} with a field path to decode from.
|
||||
* <p>If you want to decode the full data instead, use:
|
||||
* <pre>
|
||||
* client.document("..").execute().map(response -> response.toEntity(..))
|
||||
* client.document("..").executeSync()
|
||||
* </pre>
|
||||
* @return a spec with decoding options
|
||||
* @throws FieldAccessException if the field has any field errors,
|
||||
@@ -256,9 +257,9 @@ public interface GraphQlClient {
|
||||
|
||||
/**
|
||||
* Shortcut for {@link #execute()} with a field path to decode from.
|
||||
* <p>If you want to decode the full data instead, use {@link #execute()}:
|
||||
* <p>If you want to decode the full data instead, use:
|
||||
* <pre>
|
||||
* client.document("..").execute().map(response -> response.toEntity(..))
|
||||
* client.document("..").execute().map(response -> ...)
|
||||
* </pre>
|
||||
* @return a spec with decoding options
|
||||
* @throws FieldAccessException if the field has any field errors,
|
||||
@@ -269,9 +270,9 @@ public interface GraphQlClient {
|
||||
/**
|
||||
* Shortcut for {@link #executeSubscription()} with a field path to
|
||||
* decode from for each result.
|
||||
* <p>If you want to decode the full data, use {@link #executeSubscription()}:
|
||||
* <p>If you want to decode the full data, use:
|
||||
* <pre>
|
||||
* client.document("..").executeSubscription().map(response -> response.toEntity(..))
|
||||
* client.document("..").executeSubscription().map(response -> ...)
|
||||
* </pre>
|
||||
* @return a spec with decoding options
|
||||
*/
|
||||
@@ -291,8 +292,8 @@ public interface GraphQlClient {
|
||||
* Execute request with a single response, e.g. "query" or "mutation", and
|
||||
* return a response for further options.
|
||||
* @return a {@code Mono} with a {@code ClientGraphQlResponse} for further
|
||||
* decoding of the response. The {@code Mono} may end with a
|
||||
* .
|
||||
* decoding of the response. The {@code Mono} may end with an error due
|
||||
* to transport level issues.
|
||||
*/
|
||||
Mono<ClientGraphQlResponse> execute();
|
||||
|
||||
@@ -316,17 +317,17 @@ public interface GraphQlClient {
|
||||
|
||||
|
||||
/**
|
||||
* Declares options to decode a field for a single response operation.
|
||||
* Declares options to decode a field in a single response.
|
||||
* @since 1.3
|
||||
*/
|
||||
interface RetrieveSyncSpec {
|
||||
|
||||
/**
|
||||
* Decode the field to an entity of the given type.
|
||||
* @param entityType the type to convert to
|
||||
* @return {@code Mono} with the decoded entity; completes with
|
||||
* {@link FieldAccessException} in case of {@link ResponseField field
|
||||
* @return the entity or null if the field is {@code null} and has no errors.
|
||||
* @throws FieldAccessException in case of {@link ResponseField field
|
||||
* errors} or an {@link GraphQlResponse#isValid() invalid} response;
|
||||
* completes empty if the field is {@code null} but has no errors.
|
||||
* @see ResponseField#getErrors()
|
||||
*/
|
||||
@Nullable
|
||||
@@ -345,8 +346,7 @@ public interface GraphQlClient {
|
||||
<D> List<D> toEntityList(Class<D> elementType);
|
||||
|
||||
/**
|
||||
* Variant of {@link #toEntity(Class)} to decode to a List of entities.
|
||||
* @param elementType the type of elements in the list
|
||||
* Variant of {@link #toEntityList(Class)} with a {@link ParameterizedTypeReference}.
|
||||
*/
|
||||
<D> List<D> toEntityList(ParameterizedTypeReference<D> elementType);
|
||||
|
||||
@@ -354,7 +354,7 @@ public interface GraphQlClient {
|
||||
|
||||
|
||||
/**
|
||||
* Declares options to decode a field for a single response operation.
|
||||
* Declares options to decode a field in a single response.
|
||||
*/
|
||||
interface RetrieveSpec {
|
||||
|
||||
@@ -381,8 +381,7 @@ public interface GraphQlClient {
|
||||
<D> Mono<List<D>> toEntityList(Class<D> elementType);
|
||||
|
||||
/**
|
||||
* Variant of {@link #toEntity(Class)} to decode to a List of entities.
|
||||
* @param elementType the type of elements in the list
|
||||
* Variant of {@link #toEntityList(Class)} with a {@link ParameterizedTypeReference}.
|
||||
*/
|
||||
<D> Mono<List<D>> toEntityList(ParameterizedTypeReference<D> elementType);
|
||||
|
||||
|
||||
@@ -21,10 +21,12 @@ import reactor.core.publisher.Mono;
|
||||
|
||||
|
||||
/**
|
||||
* Interceptor for {@link GraphQlClient} requests.
|
||||
* Interceptor for {@link GraphQlClient} requests for use in a non-blocking
|
||||
* execution chain with a non-blocking {@link GraphQlTransport}..
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 1.0.0
|
||||
* @see GraphQlClient.Builder
|
||||
*/
|
||||
public interface GraphQlClientInterceptor {
|
||||
|
||||
@@ -54,8 +56,8 @@ public interface GraphQlClientInterceptor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@link GraphQlClientInterceptor} that invokes the current
|
||||
* interceptor first and then the one that is passed in.
|
||||
* Return a new interceptor that invokes the current interceptor first and
|
||||
* then the one that is passed in.
|
||||
* @param interceptor the interceptor to delegate to after "this"
|
||||
* @return the new {@code GraphQlClientInterceptor}
|
||||
*/
|
||||
@@ -78,7 +80,7 @@ public interface GraphQlClientInterceptor {
|
||||
|
||||
|
||||
/**
|
||||
* Contract for delegation of single response requests to the rest of the chain.
|
||||
* Contract to delegate to the rest of a non-blocking execution chain.
|
||||
*/
|
||||
interface Chain {
|
||||
|
||||
|
||||
@@ -66,14 +66,6 @@ final class HttpMessageConverterDelegate {
|
||||
.orElseThrow(() -> new IllegalArgumentException("No JSON HttpMessageConverter"));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static MediaType toMediaType(@Nullable MimeType mimeType) {
|
||||
if (mimeType instanceof MediaType mediaType) {
|
||||
return mediaType;
|
||||
}
|
||||
return (mimeType != null ? new MediaType(mimeType) : null);
|
||||
}
|
||||
|
||||
static HttpMessageConverterEncoder asEncoder(HttpMessageConverter<Object> converter) {
|
||||
return new HttpMessageConverterEncoder(converter);
|
||||
}
|
||||
@@ -82,7 +74,18 @@ final class HttpMessageConverterDelegate {
|
||||
return new HttpMessageConverterDecoder(converter);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static MediaType toMediaType(@Nullable MimeType mimeType) {
|
||||
if (mimeType instanceof MediaType mediaType) {
|
||||
return mediaType;
|
||||
}
|
||||
return (mimeType != null ? new MediaType(mimeType) : null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Partial Encoder implementation to encode a single value through an HttpMessageConverter.
|
||||
*/
|
||||
private static class HttpMessageConverterEncoder implements Encoder<Object> {
|
||||
|
||||
private final HttpMessageConverter<Object> converter;
|
||||
@@ -134,6 +137,9 @@ final class HttpMessageConverterDelegate {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Partial Decoder implementation to decode a single buffer through an HttpMessageConverter.
|
||||
*/
|
||||
private static class HttpMessageConverterDecoder implements Decoder<Object> {
|
||||
|
||||
private final HttpMessageConverter<Object> converter;
|
||||
|
||||
@@ -26,10 +26,12 @@ import org.springframework.web.client.RestClient;
|
||||
|
||||
|
||||
/**
|
||||
* GraphQL over HTTP client that uses {@link RestClient}.
|
||||
* GraphQL over HTTP client with that uses {@link RestClient} in a blocking
|
||||
* execution chain.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 1.3
|
||||
* @see SyncGraphQlTransport
|
||||
*/
|
||||
public interface HttpSyncGraphQlClient extends GraphQlClient {
|
||||
|
||||
@@ -70,24 +72,24 @@ public interface HttpSyncGraphQlClient extends GraphQlClient {
|
||||
|
||||
|
||||
/**
|
||||
* Builder for the GraphQL over HTTP client.
|
||||
* Builder for the GraphQL over HTTP client with a blocking execution chain.
|
||||
*/
|
||||
interface Builder<B extends Builder<B>> extends GraphQlClient.SyncBuilder<B> {
|
||||
|
||||
/**
|
||||
* Set the GraphQL endpoint URL as a String.
|
||||
* @param url the url to send HTTP requests to or connect over WebSocket
|
||||
* @param url the url to send HTTP requests to
|
||||
*/
|
||||
B url(String url);
|
||||
|
||||
/**
|
||||
* Set the GraphQL endpoint URL.
|
||||
* @param url the url to send HTTP requests to or connect over WebSocket
|
||||
* @param url the url to send HTTP requests to
|
||||
*/
|
||||
B url(URI url);
|
||||
|
||||
/**
|
||||
* Add the given header to HTTP requests or to the WebSocket handshake request.
|
||||
* Add the given header to HTTP requests.
|
||||
* @param name the header name
|
||||
* @param values the header values
|
||||
*/
|
||||
@@ -101,14 +103,16 @@ public interface HttpSyncGraphQlClient extends GraphQlClient {
|
||||
B headers(Consumer<HttpHeaders> headersConsumer);
|
||||
|
||||
/**
|
||||
* Configure message converters for all JSON encoding and decoding needs.
|
||||
* Configure message converters for JSON for use in the
|
||||
* {@link org.springframework.graphql.GraphQlResponse} to convert response
|
||||
* data to higher level objects.
|
||||
* @param configurer the configurer to apply
|
||||
* @return this builder
|
||||
*/
|
||||
B messageConverters(Consumer<List<HttpMessageConverter<?>>> configurer);
|
||||
|
||||
/**
|
||||
* Customize the {@code RestClient} to use.
|
||||
* Customize the underlying {@code RestClient}.
|
||||
* <p>Note that some properties of {@code RestClient.Builder} like the base URL,
|
||||
* headers, and message converters can be customized through this builder.
|
||||
* @see #url(String)
|
||||
@@ -118,7 +122,7 @@ public interface HttpSyncGraphQlClient extends GraphQlClient {
|
||||
B restClient(Consumer<RestClient.Builder> builderConsumer);
|
||||
|
||||
/**
|
||||
* Build the {@code RestClientGraphQlClient} instance.
|
||||
* Build the {@code HttpSyncGraphQlClient} instance.
|
||||
*/
|
||||
@Override
|
||||
HttpSyncGraphQlClient build();
|
||||
|
||||
@@ -29,10 +29,7 @@ import org.springframework.web.client.RestClient;
|
||||
|
||||
|
||||
/**
|
||||
* Transport for executing GraphQL over HTTP requests via {@link RestClient}.
|
||||
*
|
||||
* <p>Supports only single-response requests over HTTP POST. For subscriptions,
|
||||
* see {@link WebSocketGraphQlTransport} and {@link RSocketGraphQlTransport}.
|
||||
* Transport for GraphQL over HTTP requests executed with {@link RestClient}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 1.3
|
||||
@@ -63,12 +60,14 @@ final class HttpSyncGraphQlTransport implements SyncGraphQlTransport {
|
||||
|
||||
@Override
|
||||
public GraphQlResponse execute(GraphQlRequest request) {
|
||||
|
||||
Map<String, Object> body = this.restClient.post()
|
||||
.contentType(this.contentType)
|
||||
.accept(MediaType.APPLICATION_JSON, MediaType.APPLICATION_GRAPHQL_RESPONSE)
|
||||
.body(request.toMap())
|
||||
.retrieve()
|
||||
.body(MAP_TYPE);
|
||||
|
||||
return new ResponseMapGraphQlResponse(body != null ? body : Collections.emptyMap());
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
package org.springframework.graphql.client;
|
||||
|
||||
/**
|
||||
* Interceptor of {@link GraphQlClient} requests.
|
||||
* Interceptor of {@link GraphQlClient} requests for use in a blocking execution
|
||||
* chain with a {@link SyncGraphQlTransport}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 1.3
|
||||
@@ -27,19 +28,19 @@ public interface SyncGraphQlClientInterceptor {
|
||||
/**
|
||||
* Intercept a single response request (query and mutation operations), and
|
||||
* delegate to the rest of the chain including other interceptors followed
|
||||
* by the {@link GraphQlTransport}.
|
||||
* by the {@link SyncGraphQlTransport}.
|
||||
* @param request the request to perform
|
||||
* @param chain the rest of the chain to perform the request
|
||||
* @return the response
|
||||
* @see GraphQlClient.RequestSpec#execute()
|
||||
* @see GraphQlClient.RequestSpec#executeSync()
|
||||
*/
|
||||
default ClientGraphQlResponse intercept(ClientGraphQlRequest request, Chain chain) {
|
||||
return chain.next(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@link SyncGraphQlClientInterceptor} that invokes the current
|
||||
* interceptor first and then the one that is passed in.
|
||||
* Return a new interceptor that invokes the current interceptor first and
|
||||
* then the one that is passed in.
|
||||
* @param interceptor the interceptor to delegate to after "this"
|
||||
* @return the new interceptor instance
|
||||
*/
|
||||
@@ -56,7 +57,7 @@ public interface SyncGraphQlClientInterceptor {
|
||||
|
||||
|
||||
/**
|
||||
* Contract to delegate to the rest of the chain.
|
||||
* Contract to delegate to the rest of a blocking execution chain.
|
||||
*/
|
||||
interface Chain {
|
||||
|
||||
@@ -66,6 +67,7 @@ public interface SyncGraphQlClientInterceptor {
|
||||
* @return the GraphQL response
|
||||
* @throws GraphQlTransportException in case of errors due to transport or
|
||||
* other issues related to encoding and decoding the request and response.
|
||||
* @see GraphQlClient.RequestSpec#executeSync()
|
||||
*/
|
||||
ClientGraphQlResponse next(ClientGraphQlRequest request);
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.springframework.graphql.GraphQlResponse;
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 1.3
|
||||
* @see GraphQlClient.SyncBuilder
|
||||
*/
|
||||
public interface SyncGraphQlTransport {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -69,8 +69,9 @@ public interface WebGraphQlClient extends GraphQlClient {
|
||||
B headers(Consumer<HttpHeaders> headersConsumer);
|
||||
|
||||
/**
|
||||
* Configure the underlying {@code CodecConfigurer} to use for all JSON
|
||||
* encoding and decoding needs.
|
||||
* Configure JSON encoders and decoders for use in the
|
||||
* {@link org.springframework.graphql.GraphQlResponse} to convert response
|
||||
* data to higher level objects.
|
||||
*/
|
||||
B codecConfigurer(Consumer<CodecConfigurer> codecsConsumer);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
Reference in New Issue
Block a user