Document Spring GraphQL support
This commit documents all the features added in the previous commits: from the main infrastructure support, to testing and metrics. See gh-29140pull/29177/head
parent
c522a8007b
commit
22706057f0
@ -0,0 +1,135 @@
|
|||||||
|
[[web.graphql]]
|
||||||
|
== Spring GraphQL
|
||||||
|
If you want to build GraphQL applications, you can take advantage of Spring Boot's auto-configuration for {spring-graphql}[Spring GraphQL].
|
||||||
|
The Spring GraphQL project is based on https://github.com/graphql-java/graphql-java[GraphQL Java].
|
||||||
|
You'll need the `spring-boot-starter-graphql` starter at a minimum.
|
||||||
|
Because GraphQL is transport-agnostic, you'll also need to have one or more additional starters in your application to expose your GraphQL API over the web:
|
||||||
|
|
||||||
|
|
||||||
|
[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
|
||||||
|
|
||||||
|
|===
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[web.graphql.schema]]
|
||||||
|
=== GraphQL Schema
|
||||||
|
|
||||||
|
A Spring GraphQL application requires a defined schema at startup.
|
||||||
|
By default, you can write ".graphqls" or ".gqls" schema files under `src/main/resources/graphql/**` and Spring Boot will pick them up automatically.
|
||||||
|
You can customize the locations with configprop:spring.graphql.schema.locations[] and the file extensions with configprop:spring.graphql.schema.file-extensions[].
|
||||||
|
|
||||||
|
In the following sections, we'll consider this sample GraphQL schema, defining two types and two queries:
|
||||||
|
|
||||||
|
[source,json,indent=0,subs="verbatim,quotes"]
|
||||||
|
----
|
||||||
|
include::{docs-resources}/graphql/schema.graphqls[]
|
||||||
|
----
|
||||||
|
|
||||||
|
|
||||||
|
[[web.graphql.runtimewiring]]
|
||||||
|
=== GraphQL 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`.
|
||||||
|
Spring Boot detects such beans and adds them to the {spring-graphql-docs}#execution-graphqlsource[GraphQlSource builder].
|
||||||
|
|
||||||
|
Typically, however, applications will not implement `DataFetcher` directly and will instead create {spring-graphql-docs}#controllers[annotated controllers].
|
||||||
|
Spring Boot will automatically register `@Controller` classes with annotated handler methods and registers those as `DataFetcher`s.
|
||||||
|
Here's a sample implementation for our greeting query with a `@Controller` class:
|
||||||
|
|
||||||
|
[source,java,indent=0,subs="verbatim"]
|
||||||
|
----
|
||||||
|
include::{docs-java}/web/graphql/GreetingController.java[]
|
||||||
|
----
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[web.graphql.data-query]]
|
||||||
|
=== Querydsl and QueryByExample Repositories support
|
||||||
|
|
||||||
|
Spring Data offers support for both Querydsl and QueryByExample repositories.
|
||||||
|
Spring GraphQL can {spring-graphql-docs}#data[configure Querydsl and QueryByExample repositories as `DataFetcher`].
|
||||||
|
|
||||||
|
Spring Data repositories annotated with `@GraphQlRepository` and extending one of:
|
||||||
|
|
||||||
|
* `QuerydslPredicateExecutor`
|
||||||
|
* `ReactiveQuerydslPredicateExecutor`
|
||||||
|
* `QueryByExampleExecutor`
|
||||||
|
* `ReactiveQueryByExampleExecutor`
|
||||||
|
|
||||||
|
are detected by Spring Boot and considered as candidates for `DataFetcher` for matching top-level queries.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[web.graphql.web-endpoints]]
|
||||||
|
=== Web Endpoints
|
||||||
|
|
||||||
|
The GraphQL HTTP endpoint is at HTTP POST "/graphql" by default. The path can be customized with configprop:spring.graphql.path[].
|
||||||
|
|
||||||
|
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, no additional dependency is required
|
||||||
|
* For both, the configprop:spring.graphql.websocket.path[] application property must be set
|
||||||
|
|
||||||
|
Spring GraphQL provides a {spring-graphql-docs}#web-interception[Web Interception] model.
|
||||||
|
This is quite useful for retrieving information from an HTTP request header and set it in the GraphQL context or fetching information from the same context and writing it to a response header.
|
||||||
|
With Spring Boot, you can declare a `WebInterceptor` bean to have it registered with the web transport.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[web.graphql.cors]]
|
||||||
|
=== CORS
|
||||||
|
|
||||||
|
{spring-framework-docs}/web.html#mvc-cors[Spring MVC] and {spring-framework-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.
|
||||||
|
|
||||||
|
Spring Boot supports many configuration properties under the `spring.graphql.cors.*` namespace; here's a short configuration sample:
|
||||||
|
|
||||||
|
[source,yaml,indent=0,subs="verbatim",configblocks]
|
||||||
|
----
|
||||||
|
spring:
|
||||||
|
graphql:
|
||||||
|
cors:
|
||||||
|
allowed-origins: "https://example.org"
|
||||||
|
allowed-methods: GET,POST
|
||||||
|
max-age: 1800s
|
||||||
|
----
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[web.graphql.exception-handling]]
|
||||||
|
=== Exceptions Handling
|
||||||
|
|
||||||
|
Spring GraphQL enables applications to register one or more Spring `DataFetcherExceptionResolver` components that are invoked sequentially.
|
||||||
|
The Exception must be resolved to a list of `graphql.GraphQLError` objects, see {spring-graphql-docs}#execution-exceptions[Spring GraphQL exception handling documentation].
|
||||||
|
Spring Boot will automatically detect `DataFetcherExceptionResolver` beans and register them with the `GraphQlSource.Builder`.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[web.graphql.graphiql]]
|
||||||
|
=== GraphiQL and Schema printer
|
||||||
|
|
||||||
|
Spring GraphQL offers infrastructure for helping developers when consuming or developing a GraphQL API.
|
||||||
|
|
||||||
|
Spring GraphQL ships with a default https://github.com/graphql/graphiql[GraphiQL] page that is exposed at "/graphiql" by default.
|
||||||
|
This page is disabled by default and can be turned on with the configprop:spring.graphql.graphiql.enabled[] property.
|
||||||
|
Many applications exposing such a page will prefer a custom build.
|
||||||
|
A default implementation is very useful during development, this is why it is exposed automatically with <<using#using.devtools,`spring-boot-devtools`>> during development.
|
||||||
|
|
||||||
|
You can also choose to expose the GraphQL schema in text format at `/graphql/schema` when the configprop:spring.graphql.schema.printer.enabled[] property is enabled.
|
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2021 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.docs.features.testing.springbootapplications.springgraphqltests;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.docs.web.graphql.GreetingController;
|
||||||
|
import org.springframework.boot.test.autoconfigure.graphql.GraphQlTest;
|
||||||
|
import org.springframework.graphql.test.tester.GraphQlTester;
|
||||||
|
|
||||||
|
@GraphQlTest(GreetingController.class)
|
||||||
|
class GreetingControllerTests {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private GraphQlTester graphQlTester;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldGreetWithSpecificName() {
|
||||||
|
this.graphQlTester.query("{ greeting(name: \"Alice\") } ").execute().path("greeting").entity(String.class)
|
||||||
|
.isEqualTo("Hello, Alice!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldGreetWithDefaultName() {
|
||||||
|
this.graphQlTester.query("{ greeting } ").execute().path("greeting").entity(String.class)
|
||||||
|
.isEqualTo("Hello, Spring!");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2021 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.docs.web.graphql;
|
||||||
|
|
||||||
|
import org.springframework.graphql.data.method.annotation.Argument;
|
||||||
|
import org.springframework.graphql.data.method.annotation.QueryMapping;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
public class GreetingController {
|
||||||
|
|
||||||
|
@QueryMapping
|
||||||
|
public String greeting(@Argument String name) {
|
||||||
|
return "Hello, " + name + "!";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
type Query {
|
||||||
|
greeting(name: String! = "Spring"): String!
|
||||||
|
project(slug: ID!): Project
|
||||||
|
}
|
||||||
|
|
||||||
|
""" A Project in the Spring portfolio """
|
||||||
|
type Project {
|
||||||
|
""" Unique string id used in URLs """
|
||||||
|
slug: ID!
|
||||||
|
""" Project name """
|
||||||
|
name: String!
|
||||||
|
""" URL of the git repository """
|
||||||
|
repositoryUrl: String!
|
||||||
|
""" Current support status """
|
||||||
|
status: ProjectStatus!
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ProjectStatus {
|
||||||
|
""" Actively supported by the Spring team """
|
||||||
|
ACTIVE
|
||||||
|
""" Supported by the community """
|
||||||
|
COMMUNITY
|
||||||
|
""" Prototype, not officially supported yet """
|
||||||
|
INCUBATING
|
||||||
|
""" Project being retired, in maintenance mode """
|
||||||
|
ATTIC
|
||||||
|
""" End-Of-Lifed """
|
||||||
|
EOL
|
||||||
|
}
|
Loading…
Reference in New Issue