
org.springframework.graphql.client.GraphQlClient Maven / Gradle / Ivy
Show all versions of spring-graphql Show documentation
/*
* 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.graphql.client;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Scheduler;
import reactor.core.scheduler.Schedulers;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.graphql.GraphQlResponse;
import org.springframework.graphql.ResponseField;
import org.springframework.graphql.support.DocumentSource;
import org.springframework.graphql.support.ResourceDocumentSource;
import org.springframework.lang.Nullable;
/**
* Define a workflow to execute GraphQL requests that is independent of the
* underlying transport.
*
* For most cases, use a transport specific extension:
*
* - {@link HttpGraphQlClient}
*
- {@link WebSocketGraphQlClient}
*
*
* Alternatively, create an instance with any other transport via
* {@link #builder(GraphQlTransport)}. Or create a transport specific extension
* similar to HTTP and WebSocket.
*
* @author Rossen Stoyanchev
* @since 1.0.0
*/
public interface GraphQlClient {
/**
* Start defining a GraphQL request with the given document, which is the
* textual representation of an operation (or operations) to perform,
* including selection sets and fragments.
* @param document the document for the request
* @return spec to further define or execute the request
*/
RequestSpec document(String document);
/**
* Variant of {@link #document(String)} that uses the given key to resolve
* the GraphQL document from a file with the help of the configured
* {@link Builder#documentSource(DocumentSource) DocumentSource}.
* @param name the document name
* @throws IllegalArgumentException if the content could not be loaded
*/
RequestSpec documentName(String name);
/**
* Return a builder initialized from the configuration of "this" client
* to use to build a new, independently configured client instance.
*/
BaseBuilder> mutate();
/**
* Create a builder with the given custom {@code GraphQlTransport}.
*
For most cases, use a transport specific extension such as
* {@link HttpGraphQlClient} or {@link WebSocketGraphQlClient}. This method
* is for use with a custom {@code GraphQlTransport}.
* @param transport the transport to execute requests with
* @return the builder for further initialization
*/
static Builder> builder(GraphQlTransport transport) {
return new DefaultTransportGraphQlClientBuilder(transport);
}
/**
* Base builder for creating and initializing a {@link GraphQlClient}.
* @param the type of builder
*/
interface BaseBuilder> {
/**
* Configure a {@link DocumentSource} strategy to resolve a document by
* name. For use within {@link #documentName(String)}.
*
By default, this is set to {@link ResourceDocumentSource} with
* classpath location {@code "graphql-documents/"} and
* {@link ResourceDocumentSource#FILE_EXTENSIONS} as extensions.
* @param contentLoader the strategy for resolving documents by their names
*/
B documentSource(DocumentSource contentLoader);
/**
* Configure a timeout to use for blocking execution.
*
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 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);
/**
* Build the {@code GraphQlClient} instance.
*/
GraphQlClient build();
}
/**
* Builder to create a {@link GraphQlClient} instance with a
* synchronous execution chain and transport.
* @param the type of builder
* @see SyncGraphQlTransport
*/
interface SyncBuilder> extends BaseBuilder {
/**
* Configure interceptors to be invoked before delegating to the
* {@link SyncGraphQlTransport} to perform the request.
* @param interceptors the interceptors to add
* @return this builder
*/
B interceptor(SyncGraphQlClientInterceptor... interceptors);
/**
* Customize the list of interceptors. The provided list is "live", so
* the consumer can inspect and insert interceptors accordingly.
* @param interceptorsConsumer consumer to customize the interceptors with
* @return this builder
*/
B interceptors(Consumer> interceptorsConsumer);
/**
* The scheduler to use for non-blocking execution with
* {@link RequestSpec#execute()} and {@link RequestSpec#retrieve(String)}.
* By default this is set to {@link Schedulers#boundedElastic()}.
* @param scheduler the scheduler
*/
B scheduler(Scheduler scheduler);
}
/**
* Builder to create a {@link GraphQlClient} with a non-blocking execution
* chain and transport.
* @param the type of builder
*/
interface Builder> extends BaseBuilder {
/**
* Configure interceptors to be invoked before delegating to the
* {@link GraphQlTransport} to perform the request.
* @param interceptors the interceptors to add
* @return this builder
*/
B interceptor(GraphQlClientInterceptor... interceptors);
/**
* Customize the list of interceptors. The provided list is "live", so
* the consumer can inspect and insert interceptors accordingly.
* @param interceptorsConsumer consumer to customize the interceptors with
* @return this builder
*/
B interceptors(Consumer> interceptorsConsumer);
}
/**
* Declare options to gather input for a GraphQL request and execute it.
*/
interface RequestSpec {
/**
* Set the name of the operation in the {@link #document(String) document}
* to execute, if the document contains multiple operations.
* @param operationName the operation name
* @return this request spec
*/
RequestSpec operationName(@Nullable String operationName);
/**
* Add a value for a variable defined by the operation.
* @param name the variable name
* @param value the variable value
* @return this request spec
*/
RequestSpec variable(String name, @Nullable Object value);
/**
* Add all given values for variables defined by the operation.
* @param variables the variable values
* @return this request spec
*/
RequestSpec variables(Map variables);
/**
* Add a value for a protocol extension.
* @param name the protocol extension name
* @param value the extension value
* @return this request spec
*/
RequestSpec extension(String name, @Nullable Object value);
/**
* Add all given protocol extensions.
* @param extensions the protocol extensions
* @return this request spec
*/
RequestSpec extensions(Map extensions);
/**
* Set a client request attribute.
* This is purely for client side request processing, i.e. available
* throughout the {@link GraphQlClientInterceptor} chain but not sent.
* @param name the name of the attribute
* @param value the attribute value
* @return this builder
*/
RequestSpec attribute(String name, Object value);
/**
* Manipulate the client request attributes. The map provided to the consumer
* is "live", so the consumer can inspect and modify attributes accordingly.
* @param attributesConsumer consumer to customize attributes with
* @return this builder
*/
RequestSpec attributes(Consumer