This projects builds on Boot 2.5.x, but it should be compatible with the latest Boot 2.4.x.

Project Setup

To create a project, go to https://start.spring.io and select starter(s) for the GraphQL transports you want to use:

Starter Transport Implementation

spring-boot-starter-web

HTTP

Spring MVC

spring-boot-starter-websocket

WebSocket

WebSocket for Servlet apps

spring-boot-starter-webflux

HTTP, WebSocket

Spring WebFlux

In the generated project, add graphql-spring-boot-starter manually:

Gradle
dependencies {
	// Spring GraphQL Boot starter
	implementation 'org.springframework.experimental:graphql-spring-boot-starter:1.0.0-SNAPSHOT'

	// ...
}

repositories {
	mavenCentral()
	maven { url 'https://repo.spring.io/milestone' }  // Spring milestones
	maven { url 'https://repo.spring.io/snapshot' }   // Spring snapshots
}
Maven
<dependencies>

	// Spring GraphQL Boot starter
	<dependency>
		<groupId>org.springframework.experimental</groupId>
		<artifactId>graphql-spring-boot-starter</artifactId>
		<version>1.0.0-SNAPSHOT</version>
	</dependency>

	<!-- ... -->

</dependencies>

<!-- For Spring project milestones or snapshot releases -->
<repositories>
	<repository>
		<id>spring-milestones</id>
		<name>Spring Milestones</name>
		<url>https://repo.spring.io/milestone</url>
	</repository>
	<repository>
		<id>spring-snapshots</id>
		<name>Spring Snapshots</name>
		<url>https://repo.spring.io/snapshot</url>
		<snapshots>
			<enabled>true</enabled>
		</snapshots>
	</repository>
</repositories>
Boot Starter Group Id

The Boot starter will move from the Spring GraphQL repository to the Spring Boot repository, after Spring Boot 2.6 is released. The group id for the starter will then change from org.springframework.experimental to org.springframework.boot and will be released in Spring Boot 2.7.

Schema

By default, GraphQL schema files are expected to be in src/main/resources/graphql and have the extension ".graphqls", ".graphql", ".gql", or ".gqls". You can customize the schema locations to check as follows:

spring.graphql.schema.locations=classpath:graphql/

The GraphQL schema can be viewed over HTTP at "/graphql/schema". This is not enabled by default:

spring.graphql.schema.printer.enabled=false

RuntimeWiring

The GraphQL Java RuntimeWiring.Builder can be used to register DataFetchers, type resolvers, custom scalar types, and more. You can declare RuntimeWiringConfigurer beans in your Spring config to get access to the RuntimeWiring.Builder. The Boot starter detects such beans adds them to GraphQlSource.Builder.

Typically, however, applications will not implement DataFetcher directly and will instead create annotated controllers. The Boot starter declares a RuntimeWiringConfigurer called AnnotatedDataFetcherConfigurer that detects @Controller classes with annotated handler methods and registers those as DataFetchers.

Querydsl Repositories

Spring Data repositories that extend QuerydslPredicateExecutor or ReactiveQuerydslPredicateExecutor and are annotated with @GraphQlRepository are detected and considered as candidates for DataFetcher auto registration for matching top-level queries.

Web Endpoints

The GraphQL HTTP endpoint is at HTTP POST "/graphql" by default. The path can be customized:

spring.graphql.path=/graphql

The GraphQL WebSocket endpoint supports WebSocket handshakes at "/graphql" by default. The below shows the properties that apply for WebSocket handling:

spring.graphql.websocket.path=/graphql

# Time within which a "CONNECTION_INIT" message must be received from the client
spring.graphql.websocket.connection-init-timeout=60s

The GraphQL WebSocket endpoint is off by default. To enable it:

  • For a Servlet application, add the WebSocket starter spring-boot-starter-websocket.

  • For a WebFlux application, set the spring.graphql.websocket.path application property.

Declare a WebInterceptor bean to have it registered in the Web Interception for GraphQL over HTTP and WebSocket requests.

Declare a ThreadLocalAccessor bean to assist with the propagation of ThreadLocal values of interest in Spring MVC.

GraphiQL

The Spring Boot starter includes a GraphiQL page that is exposed at "/graphiql" by default. You can configure this as follows:

spring.graphql.graphiql.enabled=true
spring.graphql.graphiql.path=/graphiql

Metrics

When the starter spring-boot-starter-actuator is present on the classpath, metrics for GraphQL requests are collected. You can disable metrics collection as follows:

management.metrics.graphql.autotime.enabled=false

Metrics can be exposed with an Actuator web endpoint. The following sections assume that its exposure is enabled in your application configuration, as follows:

management.endpoints.web.exposure.include=health,metrics,info

Request Timer

A Request metric timer is available at /actuator/metrics/graphql.request.

Tag Description Sample values

outcome

Request outcome

"SUCCESS", "ERROR"

DataFetcher Timer

A DataFetcher metric timer is available at /actuator/metrics/graphql.datafetcher.

Tag Description Sample values

path

data fetcher path

"Query.project"

outcome

data fetching outcome

"SUCCESS", "ERROR"

Error Counter

A GraphQL error metric counter is available at /actuator/metrics/graphql.error.

Tag Description Sample values

errorType

error type

"DataFetchingException"

errorPath

error JSON Path

"$.project"

Testing

For Spring GraphQL testing support, add the below to your classpath and that will make a WebGraphQlTester available for injection into tests:

Gradle
dependencies {
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	testImplementation 'org.springframework.graphql:spring-graphql-test:1.0.0-SNAPSHOT'

	// Also add this, unless spring-boot-starter-webflux is also present
	testImplementation 'org.springframework:spring-webflux'

	// ...
}

repositories {
	mavenCentral()
	maven { url 'https://repo.spring.io/milestone' }  // Spring milestones
	maven { url 'https://repo.spring.io/snapshot' }   // Spring snapshots
}
Maven
<dependencies>

	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>
	<dependency>
		<groupId>org.springframework.graphql</groupId>
		<artifactId>spring-graphql-test</artifactId>
		<version>1.0.0-SNAPSHOT</version>
		<scope>test</scope>
	</dependency>

	<!-- Also add this, unless "spring-boot-starter-webflux" is also present -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-webflux</artifactId>
		<scope>test</scope>
	</dependency>

	<!-- ... -->

</dependencies>

<!-- For Spring project milestones or snapshot releases -->
<repositories>
	<repository>
		<id>spring-milestones</id>
		<name>Spring Milestones</name>
		<url>https://repo.spring.io/milestone</url>
	</repository>
	<repository>
		<id>spring-snapshots</id>
		<name>Spring Snapshots</name>
		<url>https://repo.spring.io/snapshot</url>
		<snapshots>
			<enabled>true</enabled>
		</snapshots>
	</repository>
</repositories>

For GraphQL over HTTP with Spring MVC, using MockMvc as the server:

@SpringBootTest
@AutoConfigureMockMvc
@AutoConfigureGraphQlTester
public class MockMvcGraphQlTests {

	@Autowired
	private WebGraphQlTester graphQlTester;

}

For GraphQL over HTTP with Spring WebFlux, using a mock server:

@SpringBootTest
@AutoConfigureWebTestClient
@AutoConfigureGraphQlTester
public class MockMvcGraphQlTests {

	@Autowired
	private WebGraphQlTester graphQlTester;

}

For GraphQL over HTTP with a running server:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureGraphQlTester
public class MockMvcGraphQlTests {

	@Autowired
	private WebGraphQlTester graphQlTester;

}

Subscriptions can be tested without WebSocket as shown below:

@SpringBootTest
@AutoConfigureGraphQlTester
public class MockMvcGraphQlTests {

	@Autowired
	private WebGraphQlTester graphQlTester;

	@Test
	void subscription() {
		Flux<String> result = this.graphQlTester.query("subscription { greetings }")
				.executeSubscription()
				.toFlux("greetings", String.class);

		// Use StepVerifier from "reactor-test" to verify the stream...
		StepVerifier.create(result)
				.expectNext("Hi")
				.expectNext("Bonjour")
				.expectNext("Hola")
				.verifyComplete();
	}

}

The above subscription test is performed directly against the WebGraphQlHandler that both HTTP and WebSocket transports delegate to. It passes through the WebInterceptor chain and then calls GraphQL Java which returns a Reactive Streams Publisher.