Reinstate Spring for GraphQL auto-configuration
This commit adds the Spring for GraphQL auto-configuration back into Spring Boot 3.0, now that a 1.1.0 release is scheduled with the required baseline. This release also needs GraphQL Java 19.0 as a baseline. Closes gh-31809
This commit is contained in:
@@ -888,6 +888,55 @@ NOTE: Only caches that are configured on startup are bound to the registry.
|
||||
For caches not defined in the cache’s configuration, such as caches created on the fly or programmatically after the startup phase, an explicit registration is required.
|
||||
A `CacheMetricsRegistrar` bean is made available to make that process easier.
|
||||
|
||||
[[actuator.metrics.supported.spring-graphql]]
|
||||
==== Spring GraphQL Metrics
|
||||
Auto-configuration enables the instrumentation of GraphQL queries, for any supported transport.
|
||||
|
||||
Spring Boot records a `graphql.request` timer with:
|
||||
|
||||
[cols="1,2,2"]
|
||||
|===
|
||||
|Tag | Description| Sample values
|
||||
|
||||
|outcome
|
||||
|Request outcome
|
||||
|"SUCCESS", "ERROR"
|
||||
|===
|
||||
|
||||
A single GraphQL query can involve many `DataFetcher` calls, so there is a dedicated `graphql.datafetcher` timer:
|
||||
|
||||
[cols="1,2,2"]
|
||||
|===
|
||||
|Tag | Description| Sample values
|
||||
|
||||
|path
|
||||
|data fetcher path
|
||||
|"Query.project"
|
||||
|
||||
|outcome
|
||||
|data fetching outcome
|
||||
|"SUCCESS", "ERROR"
|
||||
|===
|
||||
|
||||
|
||||
The `graphql.request.datafetch.count` https://micrometer.io/docs/concepts#_distribution_summaries[distribution summary] counts the number of non-trivia
|
||||
This metric is useful for detecting "N+1" data fetching issues and considering batch loading; it provides the `"TOTAL"` number of data fetcher calls ma
|
||||
More options are available for <<application-properties#application-properties.actuator.management.metrics.distribution.maximum-expected-value, configu
|
||||
|
||||
A single response can contain many GraphQL errors, counted by the `graphql.error` counter:
|
||||
|
||||
[cols="1,2,2"]
|
||||
|===
|
||||
|Tag | Description| Sample values
|
||||
|
||||
|errorType
|
||||
|error type
|
||||
|"DataFetchingException"
|
||||
|
||||
|errorPath
|
||||
|error JSON Path
|
||||
|"$.project"
|
||||
|===
|
||||
|
||||
|
||||
[[actuator.metrics.supported.jdbc]]
|
||||
|
||||
@@ -83,6 +83,9 @@
|
||||
:spring-framework: https://spring.io/projects/spring-framework
|
||||
:spring-framework-api: https://docs.spring.io/spring-framework/docs/{spring-framework-version}/javadoc-api/org/springframework
|
||||
:spring-framework-docs: https://docs.spring.io/spring-framework/docs/{spring-framework-version}/reference/html
|
||||
:spring-graphql: https://spring.io/projects/spring-graphql
|
||||
:spring-graphql-api: https://docs.spring.io/spring-graphql/docs/{spring-graphql-version}/api/
|
||||
:spring-graphql-docs: https://docs.spring.io/spring-graphql/docs/{spring-graphql-version}/reference/html/
|
||||
:spring-integration: https://spring.io/projects/spring-integration
|
||||
:spring-integration-docs: https://docs.spring.io/spring-integration/docs/{spring-integration-version}/reference/html/
|
||||
:spring-kafka-docs: https://docs.spring.io/spring-kafka/docs/{spring-kafka-version}/reference/html/
|
||||
|
||||
@@ -405,6 +405,42 @@ TIP: Sometimes writing Spring WebFlux tests is not enough; Spring Boot can help
|
||||
|
||||
|
||||
|
||||
[[features.testing.spring-boot-applications.spring-graphql-tests]]
|
||||
==== Auto-configured Spring GraphQL Tests
|
||||
Spring GraphQL offers a dedicated testing support module; you'll need to add it to your project:
|
||||
|
||||
.Maven
|
||||
[source,xml,indent=0,subs="verbatim"]
|
||||
----
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.graphql</groupId>
|
||||
<artifactId>spring-graphql-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- Unless already present in the compile scope -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
----
|
||||
|
||||
.Gradle
|
||||
[source,gradle,indent=0,subs="verbatim"]
|
||||
----
|
||||
dependencies {
|
||||
testImplementation("org.springframework.graphql:spring-graphql-test")
|
||||
// Unless already present in the implementation configuration
|
||||
testImplementation("org.springframework.boot:spring-boot-starter-webflux")
|
||||
}
|
||||
----
|
||||
|
||||
This testing module ships the {spring-graphql-docs}/#testing-graphqltester[GraphQlTester].
|
||||
spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/testing.adoc
|
||||
|
||||
|
||||
[[features.testing.spring-boot-applications.autoconfigured-spring-data-cassandra]]
|
||||
==== Auto-configured Data Cassandra Tests
|
||||
You can use `@DataCassandraTest` to test Cassandra applications.
|
||||
|
||||
@@ -19,6 +19,8 @@ include::web/spring-security.adoc[]
|
||||
|
||||
include::web/spring-session.adoc[]
|
||||
|
||||
include::web/spring-graphql.adoc[]
|
||||
|
||||
include::web/spring-hateoas.adoc[]
|
||||
|
||||
include::web/whats-next.adoc[]
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
[[web.graphql]]
|
||||
== Spring for GraphQL
|
||||
If you want to build GraphQL applications, you can take advantage of Spring Boot's auto-configuration for {spring-graphql}[Spring for GraphQL].
|
||||
The Spring for 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
|
||||
|
||||
| `spring-boot-starter-rsocket`
|
||||
| TCP, WebSocket
|
||||
| Spring WebFlux on Reactor Netty
|
||||
|===
|
||||
|
||||
|
||||
|
||||
[[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[]
|
||||
----
|
||||
|
||||
NOTE: By default, https://spec.graphql.org/draft/#sec-Introspection[field introspection] will be allowed on the schema as it is required for tools such as GraphiQL.
|
||||
If you wish to not expose information about the schema, you can disable introspection by setting configprop:spring.graphql.schema.introspection.enabled[] to `false`.
|
||||
|
||||
|
||||
|
||||
[[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 detect `@Controller` classes with annotated handler methods and register those as `DataFetcher`s.
|
||||
Here's a sample implementation for our greeting query with a `@Controller` class:
|
||||
|
||||
include::code:GreetingController[]
|
||||
|
||||
|
||||
|
||||
[[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.transports]]
|
||||
=== Transports
|
||||
|
||||
|
||||
|
||||
[[web.graphql.transports.http-websocket]]
|
||||
==== HTTP and WebSocket
|
||||
The GraphQL HTTP endpoint is at HTTP POST "/graphql" by default.
|
||||
The path can be customized with configprop:spring.graphql.path[].
|
||||
|
||||
TIP: The HTTP endpoint for both Spring MVC and Spring WebFlux is provided by a `RouterFunction` bean with an `@Order` of `0`.
|
||||
If you define your own `RouterFunction` beans, you may want to add appropriate `@Order` annotations to ensure that they are sorted correctly.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
{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.transports.rsocket]]
|
||||
==== RSocket
|
||||
RSocket is also supported as a transport, on top of WebSocket or TCP.
|
||||
Once the <<messaging#messaging.rsocket.server-auto-configuration,RSocket server is configured>>, we can configure our GraphQL handler on a particular route using configprop:spring.graphql.rsocket.mapping[].
|
||||
For example, configuring that mapping as `"graphql"` means we can use that as a route when sending requests with the `RSocketGraphQlClient`.
|
||||
|
||||
Spring Boot auto-configures a `RSocketGraphQlClient.Builder<?>` bean that you can inject in your components:
|
||||
|
||||
include::code:RSocketGraphQlClientExample[tag=builder]
|
||||
|
||||
And then send a request:
|
||||
include::code:RSocketGraphQlClientExample[tag=request]
|
||||
|
||||
|
||||
|
||||
[[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,40 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.test.autoconfigure.graphql.tester.AutoConfigureHttpGraphQlTester;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.graphql.test.tester.HttpGraphQlTester;
|
||||
|
||||
@AutoConfigureHttpGraphQlTester
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
|
||||
class GraphQlIntegrationTests {
|
||||
|
||||
@Test
|
||||
void shouldGreetWithSpecificName(@Autowired HttpGraphQlTester graphQlTester) {
|
||||
HttpGraphQlTester authenticatedTester = graphQlTester.mutate()
|
||||
.webTestClient(
|
||||
(client) -> client.defaultHeaders((headers) -> headers.setBasicAuth("admin", "ilovespring")))
|
||||
.build();
|
||||
authenticatedTester.document("{ greeting(name: \"Alice\") } ").execute().path("greeting").entity(String.class)
|
||||
.isEqualTo("Hello, Alice!");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.runtimewiring.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.document("{ greeting(name: \"Alice\") } ").execute().path("greeting").entity(String.class)
|
||||
.isEqualTo("Hello, Alice!");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldGreetWithDefaultName() {
|
||||
this.graphQlTester.document("{ greeting } ").execute().path("greeting").entity(String.class)
|
||||
.isEqualTo("Hello, Spring!");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.runtimewiring;
|
||||
|
||||
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,49 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.transports.rsocket;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.graphql.client.RSocketGraphQlClient;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
// tag::builder[]
|
||||
@Component
|
||||
public class RSocketGraphQlClientExample {
|
||||
|
||||
private final RSocketGraphQlClient graphQlClient;
|
||||
|
||||
public RSocketGraphQlClientExample(RSocketGraphQlClient.Builder<?> builder) {
|
||||
this.graphQlClient = builder.tcp("example.spring.io", 8181).route("graphql").build();
|
||||
}
|
||||
// end::builder[]
|
||||
|
||||
public void rsocketOverTcp() {
|
||||
// tag::request[]
|
||||
Mono<Book> book = this.graphQlClient.document("{ bookById(id: \"book-1\"){ id name pageCount author } }")
|
||||
.retrieve("bookById").toEntity(Book.class);
|
||||
// end::request[]
|
||||
book.block(Duration.ofSeconds(5));
|
||||
}
|
||||
|
||||
static class Book {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.test.autoconfigure.graphql.tester.AutoConfigureHttpGraphQlTester
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.graphql.test.tester.HttpGraphQlTester
|
||||
import org.springframework.http.HttpHeaders
|
||||
import org.springframework.test.web.reactive.server.WebTestClient
|
||||
|
||||
@AutoConfigureHttpGraphQlTester
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
|
||||
class GraphQlIntegrationTests {
|
||||
|
||||
@Test
|
||||
fun shouldGreetWithSpecificName(@Autowired graphQlTester: HttpGraphQlTester) {
|
||||
val authenticatedTester = graphQlTester.mutate()
|
||||
.webTestClient { client: WebTestClient.Builder ->
|
||||
client.defaultHeaders { headers: HttpHeaders ->
|
||||
headers.setBasicAuth("admin", "ilovespring")
|
||||
}
|
||||
}.build()
|
||||
authenticatedTester.document("{ greeting(name: \"Alice\") } ").execute()
|
||||
.path("greeting").entity(String::class.java).isEqualTo("Hello, Alice!")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.runtimewiring.GreetingController
|
||||
import org.springframework.boot.test.autoconfigure.graphql.GraphQlTest
|
||||
import org.springframework.graphql.test.tester.GraphQlTester
|
||||
|
||||
@GraphQlTest(GreetingController::class)
|
||||
internal class GreetingControllerTests {
|
||||
|
||||
@Autowired
|
||||
lateinit var graphQlTester: GraphQlTester
|
||||
|
||||
@Test
|
||||
fun shouldGreetWithSpecificName() {
|
||||
graphQlTester.document("{ greeting(name: \"Alice\") } ").execute().path("greeting").entity(String::class.java)
|
||||
.isEqualTo("Hello, Alice!")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldGreetWithDefaultName() {
|
||||
graphQlTester.document("{ greeting } ").execute().path("greeting").entity(String::class.java)
|
||||
.isEqualTo("Hello, Spring!")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.runtimewiring;
|
||||
|
||||
import org.springframework.graphql.data.method.annotation.Argument
|
||||
import org.springframework.graphql.data.method.annotation.QueryMapping
|
||||
import org.springframework.stereotype.Controller
|
||||
|
||||
@Controller
|
||||
class GreetingController {
|
||||
|
||||
@QueryMapping
|
||||
fun greeting(@Argument name: String): String {
|
||||
return "Hello, $name!"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.transports.rsocket
|
||||
|
||||
import org.springframework.graphql.client.RSocketGraphQlClient
|
||||
import org.springframework.stereotype.Component
|
||||
import java.time.Duration
|
||||
|
||||
// tag::builder[]
|
||||
@Component
|
||||
class RSocketGraphQlClientExample(private val builder: RSocketGraphQlClient.Builder<*>) {
|
||||
// end::builder[]
|
||||
|
||||
val graphQlClient = builder.tcp("example.spring.io", 8181)
|
||||
.route("graphql")
|
||||
.build()
|
||||
|
||||
fun rsocketOverTcp() {
|
||||
// tag::request[]
|
||||
val book = graphQlClient.document(
|
||||
"""
|
||||
{
|
||||
bookById(id: "book-1"){
|
||||
id
|
||||
name
|
||||
pageCount
|
||||
author
|
||||
}
|
||||
}
|
||||
"""
|
||||
)
|
||||
.retrieve("bookById").toEntity(Book::class.java)
|
||||
// end::request[]
|
||||
book.block(Duration.ofSeconds(5))
|
||||
}
|
||||
|
||||
internal class Book
|
||||
}
|
||||
Reference in New Issue
Block a user