diff --git a/spring-graphql-docs/src/docs/asciidoc/index.adoc b/spring-graphql-docs/src/docs/asciidoc/index.adoc index 6a04e2a8..96171c54 100644 --- a/spring-graphql-docs/src/docs/asciidoc/index.adoc +++ b/spring-graphql-docs/src/docs/asciidoc/index.adoc @@ -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 ---- - - org.springframework.experimental - graphql-spring-boot-starter - 1.0.0-SNAPSHOT - - - - org.springframework.boot - spring-boot-starter-web - - - - org.springframework.boot - spring-boot-starter-webflux - - + // Spring GraphQL Boot starter + + org.springframework.experimental + graphql-spring-boot-starter + 1.0.0-SNAPSHOT + + + + - + - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + true + + ---- -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 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 ----