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:
@@ -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
|
||||
----
|
||||
|
||||
Reference in New Issue
Block a user