Files
spring-graphql/spring-graphql-docs/src/docs/asciidoc/boot-starter.adoc
Rossen Stoyanchev b021663f5b Update docs for batch loading
Closes gh-63
2021-09-15 15:54:00 +01:00

458 lines
12 KiB
Plaintext

[[boot-graphql]]
= Boot Starter
This projects builds on Boot 2.5.x, but it should be compatible with the latest Boot 2.4.x.
[[boot-graphql-project]]
== Project Setup
To create a project, go to https://start.spring.io and select starter(s) for the
GraphQL transports you want to use:
[cols="1,1,1"]
|===
| 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:
[source,groovy,indent=0,subs="verbatim,quotes",role="primary"]
.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
}
----
[source,xml,indent=0,subs="verbatim,quotes",role="secondary"]
.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>
----
[NOTE]
.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.
====
[[boot-graphql-schema]]
== 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:
[source,properties,indent=0,subs="verbatim,quotes"]
----
spring.graphql.schema.locations=classpath:graphql/
----
The GraphQL schema can be viewed over HTTP at "/graphql/schema". This is not enabled by
default:
[source,properties,indent=0,subs="verbatim,quotes"]
----
spring.graphql.schema.printer.enabled=false
----
[[boot-graphql-runtimewiring]]
== RuntimeWiring
The GraphQL Java `RuntimeWiring.Builder` can be used to register ``DataFetcher``s,
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 <<execution-graphqlsource,GraphQlSource.Builder>>.
Typically, however, applications will not implement ``DataFetcher`` directly and will
instead create <<controllers,annotated controllers>>. The Boot
starter declares a `RuntimeWiringConfigurer` called `AnnotatedDataFetcherConfigurer` that
detects `@Controller` classes with annotated handler methods and registers those as
``DataFetcher``s.
[[boot-repositories-querydsl]]
== Querydsl Repositories
Spring Data repositories that extend `QuerydslPredicateExecutor` or
`ReactiveQuerydslPredicateExecutor` and are annotated with `@GraphQlRepository` are
detected and considered as candidates for `DataFetcher`
<<index.adoc#data-querydsl-registration,auto registration>> for matching top-level queries.
[[boot-graphql-web]]
== Web Endpoints
The GraphQL HTTP endpoint is at HTTP POST "/graphql" by default. The path can be customized:
[source,properties,indent=0,subs="verbatim,quotes"]
----
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:
[source,properties,indent=0,subs="verbatim,quotes"]
----
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
<<index.adoc#web-interception,Web Interception>> for GraphQL over HTTP and WebSocket
requests.
Declare a `ThreadLocalAccessor` bean to assist with the propagation of `ThreadLocal`
values of interest in <<index.adoc#execution-context-webmvc,Spring MVC>>.
[[boot-graphql-exception-handling]]
== Exception
Spring GraphQL 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. See
<<execution-exceptions>> for details.
The Boot starter detects beans of type `DataFetcherExceptionResolver` and registers them
automatically with the `GraphQlSource.Builder`.
[[boot-graphql-batch-loader-registry]]
== BatchLoaderRegistry
Spring GraphQL supports the GraphQL Java <<execution-batching,batch feature>> and provides
a `BatchLoaderRegistry` to store registrations of batch loading functions. The Boot
starter declares a `BatchLoaderRegistry` bean and configures the `ExecutionGraphQlService`
with it so that applications can simply autowire the registry into their controllers and
register batch loading functions.
For example:
[source,java,indent=0,subs="verbatim,quotes"]
----
@Controller
public class BookController {
public BookController(BatchLoaderRegistry registry) {
registry.forTypePair(Long.class, Author.class).registerBatchLoader((authorIds, env) -> {
// load authors
});
}
@SchemaMapping
public CompletableFuture<Author> author(Book book, DataLoader<Long, Author> loader) {
return loader.load(book.getAuthorId());
}
}
----
[[boot-graphql-graphiql]]
== GraphiQL
The Spring Boot starter includes a https://github.com/graphql/graphiql[GraphiQL] page
that is exposed at "/graphiql" by default. You can configure this as follows:
[source,properties,indent=0,subs="verbatim,quotes"]
----
spring.graphql.graphiql.enabled=true
spring.graphql.graphiql.path=/graphiql
----
[[boot-graphql-metrics]]
== 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:
[source,properties,indent=0,subs="verbatim,quotes"]
----
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:
[source,properties,indent=0,subs="verbatim,quotes"]
----
management.endpoints.web.exposure.include=health,metrics,info
----
[[boot-graphql-metrics-request-timer]]
=== Request Timer
A Request metric timer is available at `/actuator/metrics/graphql.request`.
[cols="1,2,2"]
|===
|Tag | Description| Sample values
|outcome
|Request outcome
|"SUCCESS", "ERROR"
|===
[[boot-graphql-metrics-datafetcher-timer]]
=== `DataFetcher` Timer
A `DataFetcher` metric timer is available at `/actuator/metrics/graphql.datafetcher`.
[cols="1,2,2"]
|===
|Tag | Description| Sample values
|path
|data fetcher path
|"Query.project"
|outcome
|data fetching outcome
|"SUCCESS", "ERROR"
|===
[[boot-graphql-metrics-error-counter]]
=== Error Counter
A GraphQL error metric counter is available at `/actuator/metrics/graphql.error`.
[cols="1,2,2"]
|===
|Tag | Description| Sample values
|errorType
|error type
|"DataFetchingException"
|errorPath
|error JSON Path
|"$.project"
|===
[[boot-graphql-testing]]
== Testing
For Spring GraphQL testing support, add the below to your classpath and that will make
a `WebGraphQlTester` available for injection into tests:
[source,groovy,indent=0,subs="verbatim,quotes",role="primary"]
.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
}
----
[source,xml,indent=0,subs="verbatim,quotes",role="secondary"]
.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:
[source,java,indent=0,subs="verbatim,quotes"]
----
@SpringBootTest
@AutoConfigureMockMvc
@AutoConfigureGraphQlTester
public class MockMvcGraphQlTests {
@Autowired
private WebGraphQlTester graphQlTester;
}
----
For GraphQL over HTTP with Spring WebFlux, using a
https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.testing.spring-boot-applications.with-mock-environment[mock server]:
[source,java,indent=0,subs="verbatim,quotes"]
----
@SpringBootTest
@AutoConfigureWebTestClient
@AutoConfigureGraphQlTester
public class MockMvcGraphQlTests {
@Autowired
private WebGraphQlTester graphQlTester;
}
----
For GraphQL over HTTP with a
https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.testing.spring-boot-applications.with-running-server[running server]:
[source,java,indent=0,subs="verbatim,quotes"]
----
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureGraphQlTester
public class MockMvcGraphQlTests {
@Autowired
private WebGraphQlTester graphQlTester;
}
----
Subscriptions can be tested without WebSocket as shown below:
[source,java,indent=0,subs="verbatim,quotes"]
----
@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`.