Remove Spring Boot Experimental Starter
The Experimental Spring Boot Starter for Spring GraphQL has been moved to Spring Boot and will be released with Spring Boot 2.7.0. Closes gh-207
This commit is contained in:
@@ -1,582 +0,0 @@
|
||||
[[boot-graphql]]
|
||||
= Boot Starter
|
||||
|
||||
This projects builds on Boot 2.6.x, but it should be compatible with the latest Boot 2.4.x.
|
||||
For QueryDSL-related features, Spring Data 2021.1.0 or later is required.
|
||||
|
||||
|
||||
|
||||
[[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,attributes",role="primary"]
|
||||
.Gradle
|
||||
----
|
||||
dependencies {
|
||||
// Spring GraphQL Boot starter
|
||||
implementation 'org.springframework.experimental:graphql-spring-boot-starter:{spring-graphql-version}'
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
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,attributes",role="secondary"]
|
||||
.Maven
|
||||
----
|
||||
<dependencies>
|
||||
|
||||
<!-- Spring GraphQL Boot starter -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.experimental</groupId>
|
||||
<artifactId>graphql-spring-boot-starter</artifactId>
|
||||
<version>{spring-graphql-version}</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, the Boot starter checks in `src/main/resources/graphql` for GraphQL schema
|
||||
files with extensions ".graphqls" or ".gqls". To customize this, use the following:
|
||||
|
||||
[source,properties,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
spring.graphql.schema.locations=classpath:graphql/
|
||||
spring.graphql.schema.fileExtensions=.graphqls, .gqls
|
||||
----
|
||||
|
||||
The GraphQL schema can be viewed at HTTP GET /graphql/schema. This is off by default and
|
||||
needs to be enabled:
|
||||
|
||||
[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 custom scalar types,
|
||||
directives, type resolvers, ``DataFetcher``s, and more. You can declare `RuntimeWiringConfigurer`
|
||||
beans in your Spring config to get access to the `RuntimeWiring.Builder`. The Boot
|
||||
starter detects such beans and adds them to <<index#execution-graphqlsource,GraphQlSource.Builder>>.
|
||||
|
||||
Typically, however, applications will not implement ``DataFetcher`` directly and will
|
||||
instead create <<index#controllers,annotated controllers>>. The Boot
|
||||
starter declares a `RuntimeWiringConfigurer` called `AnnotatedControllerConfigurer` that
|
||||
detects `@Controller` classes with annotated handler methods and registers those as
|
||||
``DataFetcher``s.
|
||||
|
||||
|
||||
[[boot-graphql-runtimewiring-scalar]]
|
||||
=== Scalar Types
|
||||
|
||||
`RuntimeWiringConfigurer` can be used to register custom scalar types:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
@Bean
|
||||
RuntimeWiringConfigurer runtimeWiringConfigurer() {
|
||||
GraphQLScalarType scalarType = ...;
|
||||
return (wiringBuilder) -> wiringBuilder.scalar(scalarType);
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
|
||||
|
||||
[[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-repositories-querybyexample]]
|
||||
== Query by Example Repositories
|
||||
|
||||
Spring Data repositories that extend `QueryByExampleExecutor` or
|
||||
`ReactiveQueryByExampleExecutor` and are annotated with `@GraphQlRepository` are
|
||||
detected and considered as candidates for `DataFetcher`
|
||||
<<index.adoc#data-querybyexample-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#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-cors]]
|
||||
== CORS
|
||||
|
||||
{spring-framework-ref-docs}/web.html#mvc-cors[Spring MVC] and
|
||||
{spring-framework-ref-docs}/web-reactive.html#webflux-cors[Spring WebFlux] support CORS
|
||||
(Cross-Origin Resource Sharing) requests. CORS is a critical part of the web config for
|
||||
GraphQL applications that are accessed from browsers using different domains.
|
||||
|
||||
The Boot starter supports the following CORS properties:
|
||||
|
||||
[source,properties,indent=0,subs="verbatim"]
|
||||
----
|
||||
spring.graphql.cors.allowed-origins=https://example.org # Comma-separated list of origins to allow. '*' allows all origins.
|
||||
spring.graphql.cors.allowed-origin-patterns= # Comma-separated list of origin patterns like 'https://*.example.com' to allow.
|
||||
spring.graphql.cors.allowed-methods=GET,POST # Comma-separated list of methods to allow. '*' allows all methods.
|
||||
spring.graphql.cors.allowed-headers= # Comma-separated list of headers to allow in a request. '*' allows all headers.
|
||||
spring.graphql.cors.exposed-headers= # Comma-separated list of headers to include in a response.
|
||||
spring.graphql.cors.allow-credentials= # Whether credentials are supported. When not set, credentials are not supported.
|
||||
spring.graphql.cors.max-age=1800s # How long the response from a pre-flight request can be cached by clients.
|
||||
----
|
||||
|
||||
TIP: For more information about the properties and their meaning, check out the
|
||||
{javadoc}/org/springframework/graphql/boot/GraphQlCorsProperties.html[GraphQlCorsProperties Javadoc].
|
||||
|
||||
|
||||
[[boot-graphql-exception-handling]]
|
||||
== Exceptions
|
||||
|
||||
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
|
||||
<<index#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 <<index#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-datafetcher-summary]]
|
||||
=== `DataFetcher` Distribution Summary
|
||||
|
||||
A https://micrometer.io/docs/concepts#_distribution_summaries[distribution summary]
|
||||
that counts the number of non-trivial `DataFetcher` calls made per request.
|
||||
This metric is useful for detecting "N+1" data fetching issues and consider batch loading;
|
||||
it provides the `"TOTAL"` number of data fetcher calls made over the `"COUNT"` of recorded requests,
|
||||
as well as the `"MAX"` calls made for a single request over the considered period.
|
||||
|
||||
The distribution is available at `/actuator/metrics/graphql.request.datafetch.count`.
|
||||
|
||||
More options are available for
|
||||
{spring-boot-ref-docs}/application-properties.html#application-properties.actuator.management.metrics.distribution.maximum-expected-value[configuring distributions with application properties].
|
||||
|
||||
|
||||
[[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
|
||||
|
||||
Spring GraphQL offers many ways to test your application: with or without a live server,
|
||||
with a Web client or without, with a Web transport or testing directly against the
|
||||
GraphQL Java engine. Tests rely on <<testing#testing-webgraphqltester,WebGraphQlTester>>, so be
|
||||
sure to become familiar with using it.
|
||||
|
||||
The Spring Boot starter will help you to configure the testing infrastructure; to start,
|
||||
add the following to your classpath:
|
||||
|
||||
[source,groovy,indent=0,subs="verbatim,quotes,attributes",role="primary"]
|
||||
.Gradle
|
||||
----
|
||||
dependencies {
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||
testImplementation 'org.springframework.graphql:spring-graphql-test:{spring-graphql-version}'
|
||||
|
||||
// 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,attributes",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>{spring-graphql-version}</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>
|
||||
----
|
||||
|
||||
The following sections cover a range of options for testing a Spring GraphQL application.
|
||||
|
||||
[[boot-graphql-testing-graphqltest]]
|
||||
=== GraphQL Slice Tests
|
||||
|
||||
Use `@GraphQlTest` on a test class to create GraphQL tests focused on GraphQL request
|
||||
execution, without involving a Web layer, and loading only a subset of the application
|
||||
configuration.
|
||||
|
||||
By default, `@GraphQlTest` limits scanning to the following beans:
|
||||
|
||||
- `@Controller`
|
||||
- `RuntimeWiringConfigurer`
|
||||
- `JsonComponent`
|
||||
- `Converter`
|
||||
- `GenericConverter`
|
||||
|
||||
Use the `controllers` attribute of `@GraphQlTest` to specify a controller class, or to
|
||||
list all data controllers required to perform requests in a test class. Leaving it empty,
|
||||
includes all controllers.
|
||||
|
||||
To add collaborator and/or other components to a test class, use one of the following:
|
||||
|
||||
- `@MockBean` fields in the test class.
|
||||
- `@Import` an `@Configuration` class into the test class.
|
||||
- Create a `@TestConfiguration` nested class.
|
||||
- Broaden the component scan via `includeFilters` on `@GraphQlTest`.
|
||||
|
||||
To add properties, use the `properties` attribute of `@GraphQlTest`, or add
|
||||
`@EnableConfigurationProperties` on the test class.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
`@GraphQlTest` is comparable to
|
||||
{spring-boot-ref-docs}/features.html#features.testing.spring-boot-applications.spring-mvc-tests[@WevMvcTest],
|
||||
which also uses test "slices" to create focused Web controller tests.
|
||||
====
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
@GraphQlTest(BookController.class)
|
||||
public class BookControllerTests {
|
||||
|
||||
@Autowired
|
||||
private GraphQlTester graphQlTester;
|
||||
|
||||
@MockBean
|
||||
private BookRepository bookRepository;
|
||||
|
||||
@Test
|
||||
void bookdByIdShouldReturnSpringBook() {
|
||||
given(this.bookRepository.findById(42L)).willReturn(new Book(42L, "Spring GraphQL"));
|
||||
String query = //
|
||||
graphQlTester.query(query).execute()
|
||||
.path("data.bookById.name").entity(String.class).isEqualTo("Spring GraphQL");
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
This mode is useful to test subscriptions without WebSocket.
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
@GraphQlTest(GreetingController.class)
|
||||
public class GreetingControllerTests {
|
||||
|
||||
@Autowired
|
||||
private GraphQlTester 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();
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
`GraphQlService` performS the above request by calling directly the GraphQL Java engine,
|
||||
which returns a Reactive Streams `Publisher`.
|
||||
|
||||
|
||||
[[boot-graphql-testing-mock]]
|
||||
=== Client and Mock Server Tests
|
||||
|
||||
You can write fuller integration tests with a Web client and a Web framework, Spring MVC or
|
||||
WebFlux, but without running a live server, i.e. using a mock request and response.
|
||||
|
||||
For GraphQL over HTTP with a {spring-boot-ref-docs}/features.html#features.testing.spring-boot-applications.with-mock-environment[mock server]:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
@SpringBootTest
|
||||
@AutoConfigureWebGraphQlTester
|
||||
public class MockWebGraphQlTests {
|
||||
|
||||
@Autowired
|
||||
private WebGraphQlTester graphQlTester;
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
|
||||
[[boot-graphql-testing-live]]
|
||||
=== Live Server Tests
|
||||
|
||||
You can also run tests against the full application infrastructure with a live server.
|
||||
Just like {spring-boot-ref-docs}/features.html#features.testing.spring-boot-applications.with-running-server[REST endpoints testing],
|
||||
you can use a `WebEnvironment.RANDOM_PORT` environment and test queries using `WebGraphQlTester`.
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
public class MockMvcGraphQlTests {
|
||||
|
||||
@Autowired
|
||||
private WebGraphQlTester graphQlTester;
|
||||
|
||||
}
|
||||
----
|
||||
@@ -1123,9 +1123,6 @@ include::testing.adoc[leveloffset=+1]
|
||||
|
||||
|
||||
|
||||
include::boot-starter.adoc[leveloffset=+1]
|
||||
|
||||
|
||||
|
||||
|
||||
[[samples]]
|
||||
|
||||
Reference in New Issue
Block a user