# Spring for GraphQL Documentation
## 1. Overview
Spring for GraphQL provides support for Spring applications built on[GraphQL Java](https://www.graphql-java.com/). It is a joint collaboration between both
teams. Our shared philosophy is to be less opinionated and more focused on
comprehensive and wide-ranging support.
Spring for GraphQL is the successor of the[GraphQL Java Spring](https://github.com/graphql-java/graphql-java-spring) project from
the GraphQL Java team. It aims to be the foundation for all Spring, GraphQL applications.
The project is in a milestone phase towards a 1.0 release, currently, and looking for
feedback. Please, use our[issue tracker](https://github.com/spring-projects/spring-graphql/issues) to report a
problem, discuss a design issue, or request a feature.
To get started, check the Spring GraphQL starter on [start.spring.io](https://start.spring.io) and the[Samples](#samples) sections.
## 2. Requirements
Spring for GraphQL requires the following as a baseline:
* JDK8
* Spring Framework 5.3
* GraphQL Java 17
* Spring Data 2021.1.0 or later for QueryDSL or Query by Example
## 3. Web Transports
Spring for GraphQL supports GraphQL requests over HTTP and over WebSocket.
### 3.1. HTTP
`GraphQlHttpHandler` handles GraphQL over HTTP requests and delegates to the[Web Interception](#web-interception) chain for request execution. There are two variants, one for
Spring MVC and one for Spring WebFlux. Both handle requests asynchronously and have
equivalent functionality, but rely on blocking vs non-blocking I/O respectively for
writing the HTTP response.
Requests must use HTTP POST with GraphQL request details included as JSON in the
request body, as defined in the proposed[GraphQL over HTTP](https://github.com/graphql/graphql-over-http/blob/main/spec/GraphQLOverHTTP.md)specification. Once the JSON body has been successfully decoded, the HTTP response
status is always 200 (OK), and any errors from GraphQL request execution appear in the
"errors" section of the GraphQL response.
`GraphQlHttpHandler` can be exposed as an HTTP endpoint by declaring a `RouterFunction`bean and using the `RouterFunctions` from Spring MVC or WebFlux to create the route. The
Boot starter does this, see the[Web Endpoints](https://docs.spring.io/spring-boot/docs/2.7.0-SNAPSHOT/reference/html/web.html#web.graphql.web-endpoints) section for
details, or check `GraphQlWebMvcAutoConfiguration` or `GraphQlWebFluxAutoConfiguration`it contains, for the actual config.
The Spring for GraphQL repository contains a Spring MVC[HTTP sample](https://github.com/spring-projects/spring-graphql/tree/main/samples/webmvc-http) application.
### 3.2. WebSocket
`GraphQlWebSocketHandler` handles GraphQL over WebSocket requests based on the[protocol](https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md) defined in the[graphql-ws](https://github.com/enisdenjo/graphql-ws) library. The main reason to use
GraphQL over WebSocket is subscriptions which allow sending a stream of GraphQL
responses, but it can also be used for regular queries with a single response.
The handler delegates every request to the [Web Interception](#web-interception) chain for further
request execution.
| |GraphQL Over WebSocket Protocols
There are two such protocols, one in the[subscriptions-transport-ws](https://github.com/apollographql/subscriptions-transport-ws)library and another in the[graphql-ws](https://github.com/enisdenjo/graphql-ws) library. The former is not active and
succeeded by the latter. Read this[blog post](https://the-guild.dev/blog/graphql-over-websockets) for the history.|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
There are two variants of `GraphQlWebSocketHandler`, one for Spring MVC and one for
Spring WebFlux. Both handle requests asynchronously and have equivalent functionality.
The WebFlux handler also uses non-blocking I/O and back pressure to stream messages,
which works well since in GraphQL Java a subscription response is a Reactive Streams`Publisher`.
The `graphql-ws` project lists a number of[recipes](https://github.com/enisdenjo/graphql-ws#recipes) for client use.
`GraphQlWebSocketHandler` can be exposed as a WebSocket endpoint by declaring a`SimpleUrlHandlerMapping` bean and using it to map the handler to a URL path. The Boot
starter has options to enable this, see the[Web Endpoints](https://docs.spring.io/spring-boot/docs/2.7.0-SNAPSHOT/reference/html/web.html#web.graphql.web-endpoints) section for
details, or check `GraphQlWebMvcAutoConfiguration` or `GraphQlWebFluxAutoConfiguration`it contains, for the actual config.
The Spring for GraphQL repository contains a WebFlux[WebSocket sample](https://github.com/spring-projects/spring-graphql/tree/main/samples/webflux-websocket) application.
### 3.3. Web Interception
[HTTP](#web-http) and [WebSocket](#web-websocket) transport handlers delegate to a common Web
interception chain for request execution. The chain consists of a sequence of`WebInterceptor` components, followed by a `GraphQlService` that invokes the GraphQL
Java engine.
`WebInterceptor` is as a common contract to use in both Spring MVC and WebFlux
applications. Use it to intercept requests, inspect HTTP request headers, or to register a
transformation of the `graphql.ExecutionInput`:
```
class MyInterceptor implements WebInterceptor {
@Override
public Mono intercept(WebInput webInput, WebInterceptorChain chain) {
webInput.configureExecutionInput((executionInput, builder) -> {
Map map = ... ;
return builder.extensions(map).build();
});
return chain.next(webInput);
}
}
```
Use `WebInterceptor` also to intercept responses, add HTTP response headers, or transform
the `graphql.ExecutionResult`:
```
class MyInterceptor implements WebInterceptor {
@Override
public Mono intercept(WebInput webInput, WebInterceptorChain chain) {
return chain.next(webInput)
.map(webOutput -> {
Object data = webOutput.getData();
Object updatedData = ... ;
return webOutput.transform(builder -> builder.data(updatedData));
});
}
}
```
`WebGraphQlHandler` provides a builder to initialize the Web interception chain. After
you build the chain, you can use the resulting `WebGraphQlHandler` to initialize the HTTP
or WebSocket transport handlers. The Boot starter configures all this, see the[Web Endpoints](https://docs.spring.io/spring-boot/docs/2.7.0-SNAPSHOT/reference/html/web.html#web.graphql.web-endpoints) section for
details, or check `GraphQlWebMvcAutoConfiguration` or `GraphQlWebFluxAutoConfiguration`it contains, for the actual config.
## 4. Request Execution
`GraphQlService` is the main Spring abstraction to call GraphQL Java to execute
requests. Underlying transports, such as the [Web Transports](#web-transports), delegate to `GraphQlService` to
handle requests.
The main implementation, `ExecutionGraphQlService`, is a thin facade around the
invocation of `graphql.GraphQL`. It is configured with a `GraphQlSource` for access to
the `graphql.GraphQL` instance.
### 4.1. `GraphQLSource`
`GraphQlSource` is a core Spring abstraction for access to the`graphql.GraphQL` instance to use for request execution. It provides a builder API to
initialize GraphQL Java and build a `GraphQlSource`.
The default `GraphQlSource` builder, accessible via `GraphQlSource.builder()`, enables
support for [Reactive `DataFetcher`](#execution-reactive-datafetcher), [Context Propagation](#execution-context), and[Exception Resolution](#execution-exceptions).
The Spring Boot [starter](https://docs.spring.io/spring-boot/docs/2.7.0-SNAPSHOT/reference/html/web.html#web.graphql) initializes a`GraphQlSource` instance through the default `GraphQlSource.Builder` and also enables
the following:
* Load [schema files](#execution-graphqlsource-schema-resources) from a configurable location.
* Expose [properties](https://docs.spring.io/spring-boot/docs/2.7.0-SNAPSHOT/reference/html/application-properties.html#appendix.application-properties.web)that apply to `GraphQlSource.Builder`.
* Detect [`RuntimeWiringConfigurer`](#execution-graphqlsource-runtimewiring-configurer) beans.
* Detect [Instrumentation](https://www.graphql-java.com/documentation/instrumentation) beans for[GraphQL metrics](https://docs.spring.io/spring-boot/docs/2.7.0-SNAPSHOT/reference/html/actuator.html#actuator.metrics.supported.spring-graphql).
* Detect `DataFetcherExceptionResolver` beans for[exception resolution](#execution-exceptions).
* Detect `GraphQlSourceBuilderCustomizer` beans for any other customizations.
#### 4.1.1. Schema Resources
`GraphQlSource.Builder` can be configured with one or more `Resource` instances to be
parsed and merged together. That means schema files can be loaded from just about any
location.
By default, the Spring Boot starter[finds schema files](https://docs.spring.io/spring-boot/docs/2.7.0-SNAPSHOT/reference/html/web.html#web.graphql.schema) from a
well-known classpath location, but you can change that to a location on the file system
via `FileSystemResource`, to byte content via `ByteArrayResource`, or implement a custom`Resource` that loads schema files from a remote location or storage.
#### 4.1.2. Schema Creation
By default, `GraphQlSource.Builder` uses the GraphQL Java `GraphQLSchemaGenerator` to
create the `graphql.schema.GraphQLSchema`. This works for most applications, but if
necessary, you can hook into the schema creation through the builder:
```
// Typically, accessed through Spring Boot's GraphQlSourceBuilderCustomizer
GraphQlSource.Builder builder = ...
builder.schemaResources(..)
.configureRuntimeWiring(..)
.schemaFactory((typeDefinitionRegistry, runtimeWiring) -> {
// create GraphQLSchema
})
```
The primary reason for this is to create the schema through a federation library.
#### 4.1.3. `RuntimeWiringConfigurer`
You can use `RuntimeWiringConfigurer` to register:
* Custom scalar types.
* Directives handling code.
* `TypeResolver`, if you need to override the[Default `TypeResolver`](#execution-graphqlsource-default-type-resolver) for a type.
* `DataFetcher` for a field, although most applications will simply configure`AnnotatedControllerConfigurer`, which detects annotated, `DataFetcher` handler methods.
The Spring Boot starter adds the `AnnotatedControllerConfigurer` by default.
The Spring Boot starter detects beans of type `RuntimeWiringConfigurer` and
registers them in the `GraphQlSource.Builder`. That means in most cases, you’ll' have
something like the following in your configuration:
```
@Configuration
public class GraphQlConfig {
@Bean
public RuntimeWiringConfigurer runtimeWiringConfigurer(BookRepository repository) {
GraphQLScalarType scalarType = ... ;
SchemaDirectiveWiring directiveWiring = ... ;
DataFetcher dataFetcher = QuerydslDataFetcher.builder(repository).single();
return wiringBuilder -> wiringBuilder
.scalar(scalarType)
.directiveWiring(directiveWiring)
.type("Query", builder -> builder.dataFetcher("book", dataFetcher));
}
}
```
If you need to add a `WiringFactory`, e.g. to make registrations that take into account
schema definitions, implement the alternative `configure` method that accepts both the`RuntimeWiring.Builder` and an output `List`. This allows you to add any
number of factories that are then invoked in sequence.
#### 4.1.4. Default `TypeResolver`
`GraphQlSource.Builder` registers `ClassNameTypeResolver` as the default `TypeResolver`to use for GraphQL Interfaces and Unions that don’t already have such a registration
through a [`RuntimeWiringConfigurer`](#execution-graphqlsource-runtimewiring-configurer). The purpose of
a `TypeResolver` in GraphQL Java is to determine the GraphQL Object type for values
returned from the `DataFetcher` for a GraphQL Interface or Union field.
`ClassNameTypeResolver` tries to match the simple class name of the value to a GraphQL
Object Type and if it is not successful, it also navigates its super types including
base classes and interfaces, looking for a match. `ClassNameTypeResolver` provides an
option to configure a name extracting function along with `Class` to GraphQL Object type
name mappings that should help to cover more corner cases.
#### 4.1.5. Operation Caching
GraphQL Java must *parse* and *validate* an operation before executing it. This may impact
performance significantly. To avoid the need to re-parse and validate, an application may
configure a `PreparsedDocumentProvider` that caches and reuses Document instances. The[GraphQL Java docs](https://www.graphql-java.com/documentation/execution/#query-caching) provide more details on
query caching through a `PreparsedDocumentProvider`.
In Spring GraphQL you can register a `PreparsedDocumentProvider` through`GraphQlSource.Builder#configureGraphQl`:
.
```
// Typically, accessed through Spring Boot's GraphQlSourceBuilderCustomizer
GraphQlSource.Builder builder = ...
// Create provider
PreparsedDocumentProvider provider = ...
builder.schemaResources(..)
.configureRuntimeWiring(..)
.configureGraphQl(graphQLBuilder -> graphQLBuilder.preparsedDocumentProvider(provider))
```
#### 4.1.6. Directives
The GraphQL language supports directives that "describe alternate runtime execution and
type validation behavior in a GraphQL document". Directives are similar to annotations in
Java but declared on types, fields, fragments and operations in a GraphQL document.
GraphQL Java provides the `SchemaDirectiveWiring` contract to help applications detect
and handle directives. For more details, see[Schema Directives](https://www.graphql-java.com/documentation/sdl-directives/) in the
GraphQL Java documentation.
In Spring GraphQL you can register a `SchemaDirectiveWiring` through a[`RuntimeWiringConfigurer`](#execution-graphqlsource-runtimewiring-configurer). The Spring Boot starter detects
such beans, so you might have something like:
```
@Configuration
public class GraphQlConfig {
@Bean
public RuntimeWiringConfigurer runtimeWiringConfigurer() {
return builder -> builder.directiveWiring(new MySchemaDirectiveWiring());
}
}
```
| |For an example of directives support check out the[Extended Validation for Graphql Java](https://github.com/graphql-java/graphql-java-extended-validation)library.|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------|
### 4.2. Reactive `DataFetcher`
The default `GraphQlSource` builder enables support for a `DataFetcher` to return `Mono`or `Flux` which adapts those to a `CompletableFuture` where `Flux` values are aggregated
and turned into a List, unless the request is a GraphQL subscription request,
in which case the return value remains a Reactive Streams `Publisher` for streaming
GraphQL responses.
A reactive `DataFetcher` can rely on access to Reactor context propagated from the
transport layer, such as from a WebFlux request handling, see[WebFlux Context](#execution-context-webflux).
### 4.3. Context Propagation
Spring for GraphQL provides support to transparently propagate context from the [Web Transports](#web-transports),
through the GraphQL engine, and to `DataFetcher` and other components it invokes.
This includes both `ThreadLocal` context from the Spring MVC request handling thread and
Reactor `Context` from the WebFlux processing pipeline.
#### 4.3.1. WebMvc
A `DataFetcher` and other components invoked by GraphQL Java may not always execute on
the same thread as the Spring MVC handler, for example if an asynchronous[`WebInterceptor`](#web-interception) or `DataFetcher` switches to a different thread.
Spring for GraphQL supports propagating `ThreadLocal` values from the Servlet container
thread to the thread a `DataFetcher` and other components invoked by the GraphQL engine
execute on. To do this, an application needs to create a `ThreadLocalAccessor` to extract`ThreadLocal` values of interest:
```
public class RequestAttributesAccessor implements ThreadLocalAccessor {
private static final String KEY = RequestAttributesAccessor.class.getName();
@Override
public void extractValues(Map container) {
container.put(KEY, RequestContextHolder.getRequestAttributes());
}
@Override
public void restoreValues(Map values) {
if (values.containsKey(KEY)) {
RequestContextHolder.setRequestAttributes((RequestAttributes) values.get(KEY));
}
}
@Override
public void resetValues(Map values) {
RequestContextHolder.resetRequestAttributes();
}
}
```
A `ThreadLocalAccessor` can be registered in the [WebGraphHandler](#web-interception)builder. The Boot starter detects beans of this type and automatically registers them for
Spring MVC application, see the[Web Endpoints](https://docs.spring.io/spring-boot/docs/2.7.0-SNAPSHOT/reference/html/web.html#web.graphql.web-endpoints) section.
#### 4.3.2. WebFlux
A [Reactive `DataFetcher`](#execution-reactive-datafetcher) can rely on access to Reactor context that
originates from the WebFlux request handling chain. This includes Reactor context
added by [WebInterceptor](#web-interception) components.
### 4.4. Exception Resolution
GraphQL Java applications can register a `DataFetcherExceptionHandler` to decide how to
represent exceptions from the data layer in the "errors" section of the GraphQL response.
Spring for GraphQL has a built-in `DataFetcherExceptionHandler` that is configured for use
by the [`GraphQLSource`](#execution-graphqlsource) builder. It enables applications to register one or
more Spring `DataFetcherExceptionResolver` components that are invoked sequentially
until one resolves the `Exception` to a list of `graphql.GraphQLError` objects.
`DataFetcherExceptionResolver` is an asynchronous contract. For most implementations, it
would be sufficient to extend `DataFetcherExceptionResolverAdapter` and override
one of its `resolveToSingleError` or `resolveToMultipleErrors` methods that
resolve exceptions synchronously.
A `GraphQLError` can be assigned an `graphql.ErrorClassification`. Spring for GraphQL
defines an `ErrorType` enum with common, error classification categories:
* `BAD_REQUEST`
* `UNAUTHORIZED`
* `FORBIDDEN`
* `NOT_FOUND`
* `INTERNAL_ERROR`
Applications can use this to classify errors. If an error remains unresolved, by
default it is marked as `INTERNAL_ERROR`.
### 4.5. Batch Loading
Given a `Book` and its `Author`, we can create one `DataFetcher` for a book and another
for its author. This allows selecting books with or without authors, but it means books
and authors aren’t loaded together, which is especially inefficient when querying multiple
books as the author for each book is loaded individually. This is known as the N+1 select
problem.
#### 4.5.1. `DataLoader`
GraphQL Java provides a `DataLoader` mechanism for batch loading of related entities.
You can find the full details in the[GraphQL Java docs](https://www.graphql-java.com/documentation/batching/). Below is a
summary of how it works:
1. Register `DataLoader`'s in the `DataLoaderRegistry` that can load entities, given unique keys.
2. `DataFetcher`'s can access `DataLoader`'s and use them to load entities by id.
3. A `DataLoader` defers loading by returning a future so it can be done in a batch.
4. `DataLoader`'s maintain a per request cache of loaded entities that can further
improve efficiency.
#### 4.5.2. `BatchLoaderRegistry`
The complete batching loading mechanism in GraphQL Java requires implementing one of
several `BatchLoader` interface, then wrapping and registering those as `DataLoader`s
with a name in the `DataLoaderRegistry`.
The API in Spring GraphQL is slightly different. For registration, there is only one,
central `BatchLoaderRegistry` exposing factory methods and a builder to create and
register any number of batch loading functions:
```
@Configuration
public class MyConfig {
public MyConfig(BatchLoaderRegistry registry) {
registry.forTypePair(Long.class, Author.class).registerMappedBatchLoader((authorIds, env) -> {
// return Mono