Restructure reference documentation

This commits sets the structure in place, moves the existing content
into its appropriate place, plus further updates to that content.

See gh-78
This commit is contained in:
Rossen Stoyanchev
2021-07-02 12:47:12 +01:00
parent f17ae9307c
commit 9a23e5f8d3

View File

@@ -6,218 +6,271 @@ Brian Clozel; Andreas Marek; Rossen Stoyanchev
:docinfo1:
https://graphql.org/[GraphQL] support for Spring applications with https://github.com/graphql-java/graphql-java[GraphQL Java].
== Getting started
== Web Transports
TODO...
=== HTTP
TODO...
=== WebSocket
TODO...
=== `WebInterceptor` API
TODO...
== Query Execution
TODO...
=== Configuring the GraphQL Engine
TODO...
=== `DataFetcher` Support
TODO...
=== Context Management
TODO...
=== Exception Resolution
TODO...
== Data Integrations
TODO...
=== QueryDsl
TODO...
== Security
TODO...
== Testing
TODO...
== Boot config
This project is tested against Spring Boot 2.4+.
You can start by creating a project on https://start.spring.io and select the `spring-boot-starter-web` or `spring-boot-starter-webflux` starter,
depending on the type of web application you'd like to build. Once the project is generated, you can manually add the
`org.springframework.experimental:graphql-spring-boot-starter` dependency.
`build.gradle` snippet:
[source,groovy,indent=0,subs="verbatim,quotes"]
=== 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 the starter `graphql-spring-boot-starter` manually:
[source,groovy,indent=0,subs="verbatim,quotes",role="primary"]
.Gradle
----
dependencies {
implementation 'org.springframework.experimental:graphql-spring-boot-starter:1.0.0-SNAPSHOT'
// Spring Web MVC starter
implementation 'org.springframework.boot:spring-boot-starter-web'
// OR Spring WebFlux starter
implementation 'org.springframework.boot:spring-boot-starter-webflux'
// Spring GraphQL Boot starter
implementation 'org.springframework.experimental:graphql-spring-boot-starter:1.0.0-SNAPSHOT'
// ...
}
repositories {
mavenCentral()
// don't forget to add spring milestone or snapshot repositories
maven { url 'https://repo.spring.io/milestone' }
maven { url 'https://repo.spring.io/snapshot' }
mavenCentral()
maven { url 'https://repo.spring.io/milestone' } // Spring milestones
maven { url 'https://repo.spring.io/snapshot' } // Spring snapshots
}
----
`pom.xml` snippet:
[source,xml,indent=0,subs="verbatim,quotes"]
[source,xml,indent=0,subs="verbatim,quotes",role="secondary"]
.Maven
----
<dependencies>
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>graphql-spring-boot-starter</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<!-- Spring Web MVC starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- OR Spring WebFlux starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<!-- ... -->
// Spring GraphQL Boot starter
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>graphql-spring-boot-starter</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<!-- ... -->
</dependencies>
<!-- Don't forget to add spring milestone or snapshot repositories -->
<!-- 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>
<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>
----
You can now add a GraphQL schema in `src/main/resources/graphql/schema.graphqls` such as:
[NOTE]
.GraphQL Spring Boot Starter Group Id
====
The starter is scheduled to move from the Spring GraphQL repository to the Spring Boot
repository, after Spring Boot 2.6 is released. The starter group id will then change
from `org.springframework.experimental` to `org.springframework.boot` and will be
released in Spring Boot 2.7 building on Spring GraphQL 1.0.
====
[source,javascript,indent=0,subs="verbatim,quotes"]
=== GraphQL 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"]
----
type Query {
people: [Person]!
}
type Person {
id: ID!
name: String!
}
spring.graphql.schema.locations=classpath:graphql/
----
Then you should configure the data fetching process using a `RuntimeWiringCustomizer` and custom components like
Spring Data repositories, `WebClient` instances for Web APIs, a `@Service` bean, etc.
The GraphQL schema can be viewed over HTTP at "/graphql/schema", if enabled:
[source,properties,indent=0,subs="verbatim,quotes"]
----
spring.graphql.schema.printer.enabled=false
----
=== `DataFetcher` Registration
You can declare `RuntimeWiringCustomizer` beans in your Spring config and use those to
register data fetchers, type resolvers, and more with the GraphQL engine:
[source,java,indent=0,subs="verbatim,quotes"]
----
@Component
public class PersonDataWiring implements RuntimeWiringCustomizer {
private final PersonService personService;
private final PersonService service;
public PersonDataWiring(PersonService personService) {
this.personService = personService;
public PersonDataWiring(PersonService service) {
this.service = service;
}
@Override
public void customize(RuntimeWiring.Builder builder) {
builder.type("Query", typeWiring -> typeWiring
.dataFetcher("people", env -> this.personService.findAll()));
builder.type("Query", wiring ->
wiring.dataFetcher("people", env -> this.service.findAll()));
}
}
----
You can now start your application!
A GraphiQL web interface is available at `http://localhost:8080/graphiql` and you can use GraphQL clients
to POST queries at the same location.
=== Web Transports
== Features
=== Core configuration
The Spring GraphQL project offers a few configuration properties to customize your application:
The GraphQL HTTP endpoint path is "/graphql" by default but can be customized:
[source,properties,indent=0,subs="verbatim,quotes"]
----
# web path to the graphql endpoint
spring.graphql.path=/graphql
# locations of the graphql schema files
# scanning for files with well-known extensions: '.graphqls', '.gqls', '.graphql', '.gql'
spring.graphql.schema.locations=classpath:graphql/
# schema printer endpoint configuration
# endpoint path is concatenated with the main path, so "/graphql/schema" by default
spring.graphql.schema.printer.enabled=false
spring.graphql.schema.printer.path=/schema
# GraphiQL UI configuration
spring.graphql.graphiql.enabled=true
spring.graphql.graphiql.path=/graphiql
# whether micrometer metrics should be collected for graphql queries
management.metrics.graphql.autotime.enabled=true
----
You can contribute `RuntimeWiringCustomizer` beans to the context in order to configure the runtime wiring of your GraphQL application.
=== WebSocket support
This project also supports WebSocket as a transport for GraphQL requests - you can use it to build http://spec.graphql.org/draft/#sec-Subscription[`Subscription` queries].
This use case is powered by Reactor `Flux`, check out the `samples/webflux-websocket` sample application for more.
To enable this support, you need to configure the `spring.graphql.websocket.path` property in your application
and have the required dependencies on classpath. In the case of a Servlet application, adding the `spring-boot-starter-websocket` should be enough.
WebSocket support comes with dedicated properties:
The GraphQL WebSocket endpoint path is "/graphql" by default. The below configuration
properties apply to the WebSocket endpoint:
[source,properties,indent=0,subs="verbatim,quotes"]
----
# Path of the GraphQL WebSocket subscription endpoint.
spring.graphql.websocket.path=/graphql/websocket
# Time within which the initial {@code CONNECTION_INIT} type message must be received.
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
----
=== Extension points
The GraphQL WebSocket endpoint is not enabled by default. To enable it:
You can contribute https://github.com/spring-projects-experimental/spring-graphql/blob/master/spring-graphql/src/main/java/org/springframework/graphql/WebInterceptor.java[`WebInterceptor` beans]
to the application context, so as to customize the `ExecutionInput` or the `ExecutionResult` of the query.
A custom `WebInterceptor` can, for example, change the HTTP request/response headers.
- For a Servlet application, add the WebSocket starter `spring-boot-starter-websocket`.
- For a WebFlux application, set the `spring.graphql.websocket.path` application property.
=== Testing support
`WebInterceptor` beans declared in Spring configuration are detected and registered to
intercept for both GraphQL requests over HTTP and over WebSocket.
When the `spring-boot-starter-test` dependency is on the classpath, Spring GraphQL provides a testing infrastructure for your application.
Spring Boot allows you to test your web application with https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.testing.spring-boot-applications.with-mock-environment[with a mock environment]
or https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.testing.spring-boot-applications.with-running-server[with a running server].
In both cases, adding the `@AutoConfigureGraphQlTester` annotation on your test class will contribute a `GraphQlTester` bean you can inject and use in your tests:
=== GraphiQL Page
[source,java,indent=0,subs="verbatim,quotes"]
The Spring Boot starter includes a https://github.com/graphql/graphiql[GraphiQL] page
that is exposed at "/graphiql" by default. You can configure that as follows:
[source,properties,indent=0,subs="verbatim,quotes"]
----
@SpringBootTest
@AutoConfigureMockMvc
@AutoConfigureGraphQlTester
public class MockMvcGraphQlTests {
@Autowired
private GraphQlTester graphQlTester;
@Test
void jsonPath() {
String query = "{" +
" project(slug:\"spring-framework\") {" +
" releases {" +
" version" +
" }" +
" }" +
"}";
this.graphQlTester.query(query)
.execute()
.path("project.releases[*].version")
.entityList(String.class)
.hasSizeGreaterThan(1);
}
}
spring.graphql.graphiql.enabled=true
spring.graphql.graphiql.path=/graphiql
----
=== Metrics
If the `spring-boot-starter-actuator` dependency is on the classpath, metrics will be collected for GraphQL requests.
You can see those metrics by exposing the metrics endpoint with `application.properties`:
When the starter `spring-boot-starter-actuator` is present on the classpath, metrics for
GraphQL requests are collected. You can configure metrics collection as follows:
[source,properties,indent=0,subs="verbatim,quotes"]
----
management.endpoints.web.exposure.include=health,metrics,info
----
==== GraphQL Request (timer)
==== GraphQL Request Timer
A Request metric timer is available at `/actuator/metrics/graphql.request`.
@@ -230,9 +283,10 @@ A Request metric timer is available at `/actuator/metrics/graphql.request`.
|"SUCCESS", "ERROR"
|===
==== GraphQL Data Fetcher (timer)
A Data Fetcher metric timer is available at `/actuator/metrics/graphql.datafetcher`.
==== GraphQL `DataFetcher` Timer
A `DataFetcher` metric timer is available at `/actuator/metrics/graphql.datafetcher`.
[cols="1,2,2"]
|===
@@ -248,9 +302,9 @@ A Data Fetcher metric timer is available at `/actuator/metrics/graphql.datafetch
|===
==== GraphQL Error (counter)
==== GraphQL Error Counter
A counter metric counter is available at `/actuator/metrics/graphql.error`.
A GraphQL error metric counter is available at `/actuator/metrics/graphql.error`.
[cols="1,2,2"]
|===
@@ -266,16 +320,102 @@ A counter metric counter is available at `/actuator/metrics/graphql.error`.
|===
== Sample applications
This repository contains sample applications that the team is using to test new features and ideas.
=== Testing
You can run them by cloning this repository and typing on the command line:
When the starter `spring-boot-starter-test` is present on the classpath, a `WebGraphQlTester`
is configured and available for injection into tests.
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 a WebSocket layer 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`.
== Samples
This Spring GraphQL repository contains
https://github.com/spring-projects/spring-graphql/tree/main/samples[sample applications] for various scenarios.
You can run those by cloning this repository and running main application classes from
your IDE or by typing the following on the command line:
[source,bash,indent=0,subs="verbatim,quotes"]
----
$ ./gradlew :samples:webmvc-http:bootRun
$ ./gradlew :samples:webflux-websocket:bootRun
$ ./gradlew :samples:webmvc-http-security:bootRun
$ ./gradlew :samples:webflux-security:bootRun
$ ./gradlew :samples:{sample-directory-name}:bootRun
----