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:
Brian Clozel
2021-12-21 14:09:17 +01:00
parent 2ded7469f4
commit a15fd29fc0
14 changed files with 21 additions and 604 deletions

View File

@@ -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;
}
----

View File

@@ -1123,9 +1123,6 @@ include::testing.adoc[leveloffset=+1]
include::boot-starter.adoc[leveloffset=+1]
[[samples]]