Move client and testing docs to compiled code snippets
Prior to this commit, the "client" and "testing" sections of the reference documentation were using inline code snippets. Because of this, several snippets were out of date or invalid. This commit moves all those code snippets to actual Java classes compiled with the documentation. Fixes gh-1042
This commit is contained in:
@@ -19,14 +19,18 @@ dependencies {
|
||||
dependencyManagement(enforcedPlatform(dependencies.project(path: ":platform")))
|
||||
api project(':spring-graphql')
|
||||
api project(':spring-graphql-test')
|
||||
api 'org.springframework:spring-webflux'
|
||||
api 'org.springframework:spring-webmvc'
|
||||
api 'org.springframework:spring-websocket'
|
||||
api 'org.springframework:spring-messaging'
|
||||
api 'org.springframework.data:spring-data-commons'
|
||||
api 'com.querydsl:querydsl-core'
|
||||
api "org.springframework.boot:spring-boot-starter-graphql:${springBootVersion}"
|
||||
api "org.springframework.boot:spring-boot-starter-web:${springBootVersion}"
|
||||
implementation 'org.springframework:spring-webflux'
|
||||
implementation 'org.springframework:spring-webmvc'
|
||||
implementation 'org.springframework:spring-websocket'
|
||||
implementation 'org.springframework:spring-messaging'
|
||||
implementation 'org.springframework.data:spring-data-commons'
|
||||
implementation 'com.querydsl:querydsl-core'
|
||||
implementation "org.springframework.boot:spring-boot-starter-graphql:${springBootVersion}"
|
||||
implementation "org.springframework.boot:spring-boot-starter-web:${springBootVersion}"
|
||||
implementation 'io.rsocket:rsocket-core'
|
||||
implementation 'io.rsocket:rsocket-transport-netty'
|
||||
implementation 'io.projectreactor:reactor-test'
|
||||
implementation 'org.assertj:assertj-core'
|
||||
}
|
||||
|
||||
jar {
|
||||
|
||||
@@ -40,35 +40,14 @@ above `GraphQlClient` extensions.
|
||||
to execute GraphQL requests over HTTP through a blocking transport contract and chain of
|
||||
interceptors.
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
RestClient restClient = ... ;
|
||||
HttpSyncGraphQlClient graphQlClient = HttpSyncGraphQlClient.create(restClient);
|
||||
----
|
||||
include-code::SyncClientUsage[tag=create,indent=0]
|
||||
|
||||
Once `HttpSyncGraphQlClient` is created, you can begin to
|
||||
xref:client.adoc#client.requests[execute requests] using the same API, independent of the underlying
|
||||
transport. If you need to change any transport specific details, use `mutate()` on an
|
||||
existing `HttpSyncGraphQlClient` to create a new instance with customized settings:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
RestClient restClient = ... ;
|
||||
|
||||
HttpSyncGraphQlClient graphQlClient = HttpSyncGraphQlClient.builder(restClient)
|
||||
.headers(headers -> headers.setBasicAuth("joe", "..."))
|
||||
.build();
|
||||
|
||||
// Perform requests with graphQlClient...
|
||||
|
||||
HttpSyncGraphQlClient anotherGraphQlClient = graphQlClient.mutate()
|
||||
.headers(headers -> headers.setBasicAuth("peter", "..."))
|
||||
.build();
|
||||
|
||||
// Perform requests with anotherGraphQlClient...
|
||||
|
||||
----
|
||||
|
||||
include-code::SyncClientUsage[tag=mutate,indent=0]
|
||||
|
||||
|
||||
[[client.httpgraphqlclient]]
|
||||
@@ -79,35 +58,14 @@ existing `HttpSyncGraphQlClient` to create a new instance with customized settin
|
||||
GraphQL requests over HTTP through a non-blocking transport contract and chain of
|
||||
interceptors.
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
WebClient webClient = ... ;
|
||||
HttpGraphQlClient graphQlClient = HttpGraphQlClient.create(webClient);
|
||||
----
|
||||
include-code::ClientUsage[tag=create,indent=0]
|
||||
|
||||
Once `HttpGraphQlClient` is created, you can begin to
|
||||
xref:client.adoc#client.requests[execute requests] using the same API, independent of the underlying
|
||||
transport. If you need to change any transport specific details, use `mutate()` on an
|
||||
existing `HttpGraphQlClient` to create a new instance with customized settings:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
WebClient webClient = ... ;
|
||||
|
||||
HttpGraphQlClient graphQlClient = HttpGraphQlClient.builder(webClient)
|
||||
.headers(headers -> headers.setBasicAuth("joe", "..."))
|
||||
.build();
|
||||
|
||||
// Perform requests with graphQlClient...
|
||||
|
||||
HttpGraphQlClient anotherGraphQlClient = graphQlClient.mutate()
|
||||
.headers(headers -> headers.setBasicAuth("peter", "..."))
|
||||
.build();
|
||||
|
||||
// Perform requests with anotherGraphQlClient...
|
||||
|
||||
----
|
||||
|
||||
include-code::ClientUsage[tag=mutate,indent=0]
|
||||
|
||||
|
||||
[[client.websocketgraphqlclient]]
|
||||
@@ -118,13 +76,7 @@ It is built using the
|
||||
{spring-framework-ref-docs}/web/webflux-websocket.html#webflux-websocket-client[WebSocketClient]
|
||||
from Spring WebFlux and you can create it as follows:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
String url = "wss://localhost:8080/graphql";
|
||||
WebSocketClient client = new ReactorNettyWebSocketClient();
|
||||
|
||||
WebSocketGraphQlClient graphQlClient = WebSocketGraphQlClient.builder(url, client).build();
|
||||
----
|
||||
include-code::WebSocketClientUsage[tag=create,indent=0]
|
||||
|
||||
In contrast to `HttpGraphQlClient`, the `WebSocketGraphQlClient` is connection oriented,
|
||||
which means it needs to establish a connection before making any requests. As you begin
|
||||
@@ -146,37 +98,12 @@ xref:client.adoc#client.requests[execute requests] using the same API, independe
|
||||
transport. If you need to change any transport specific details, use `mutate()` on an
|
||||
existing `WebSocketGraphQlClient` to create a new instance with customized settings:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
URI url = ... ;
|
||||
WebSocketClient client = ... ;
|
||||
|
||||
WebSocketGraphQlClient graphQlClient = WebSocketGraphQlClient.builder(url, client)
|
||||
.headers(headers -> headers.setBasicAuth("joe", "..."))
|
||||
.build();
|
||||
|
||||
// Use graphQlClient...
|
||||
|
||||
WebSocketGraphQlClient anotherGraphQlClient = graphQlClient.mutate()
|
||||
.headers(headers -> headers.setBasicAuth("peter", "..."))
|
||||
.build();
|
||||
|
||||
// Use anotherGraphQlClient...
|
||||
|
||||
----
|
||||
include-code::WebSocketClientUsage[tag=mutate,indent=0]
|
||||
|
||||
`WebSocketGraphQlClient` supports sending periodic ping messages to keep the connection
|
||||
active when no other messages are sent or received. You can enable that as follows:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
URI url = ... ;
|
||||
WebSocketClient client = ... ;
|
||||
|
||||
WebSocketGraphQlClient graphQlClient = WebSocketGraphQlClient.builder(url, client)
|
||||
.keepAlive(Duration.ofSeconds(30))
|
||||
.build();
|
||||
----
|
||||
include-code::WebSocketClientUsage[tag=keepAlive,indent=0]
|
||||
|
||||
|
||||
[[client.websocketgraphqlclient.interceptor]]
|
||||
@@ -220,15 +147,7 @@ can be at most one interceptor of type `WebSocketGraphQlClientInterceptor`.
|
||||
{spring-framework-ref-docs}/rsocket.html#rsocket-requester[RSocketRequester]
|
||||
to execute GraphQL requests over RSocket requests.
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
URI uri = URI.create("wss://localhost:8080/rsocket");
|
||||
WebsocketClientTransport transport = WebsocketClientTransport.create(url);
|
||||
|
||||
RSocketGraphQlClient client = RSocketGraphQlClient.builder()
|
||||
.clientTransport(transport)
|
||||
.build();
|
||||
----
|
||||
include-code::RSocketClientUsage[tag=create,indent=0]
|
||||
|
||||
In contrast to `HttpGraphQlClient`, the `RSocketGraphQlClient` is connection oriented,
|
||||
which means it needs to establish a session before making any requests. As you begin
|
||||
@@ -266,7 +185,6 @@ builders of all extensions. Currently, it has lets you configure:
|
||||
|
||||
|
||||
|
||||
|
||||
[[client.requests]]
|
||||
== Requests
|
||||
|
||||
@@ -287,36 +205,14 @@ Sync::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
----
|
||||
String document = "{" +
|
||||
" project(slug:\"spring-framework\") {" +
|
||||
" name" +
|
||||
" releases {" +
|
||||
" version" +
|
||||
" }"+
|
||||
" }" +
|
||||
"}";
|
||||
|
||||
Project project = graphQlClient.document(document) <1>
|
||||
.retrieveSync("project") <2>
|
||||
.toEntity(Project.class); <3>
|
||||
include::{include-java}/client/requests/retrieve/Retrieve.java[tag=retrieveSync,indent=0]
|
||||
----
|
||||
|
||||
Non-Blocking::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
----
|
||||
String document = "{" +
|
||||
" project(slug:\"spring-framework\") {" +
|
||||
" name" +
|
||||
" releases {" +
|
||||
" version" +
|
||||
" }"+
|
||||
" }" +
|
||||
"}";
|
||||
|
||||
Mono<Project> projectMono = graphQlClient.document(document) <1>
|
||||
.retrieve("project") <2>
|
||||
.toEntity(Project.class); <3>
|
||||
include::{include-java}/client/requests/retrieve/Retrieve.java[tag=retrieve,indent=0]
|
||||
----
|
||||
======
|
||||
|
||||
@@ -342,32 +238,14 @@ Sync::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
----
|
||||
try {
|
||||
Project project = graphQlClient.document(document)
|
||||
.retrieveSync("project")
|
||||
.toEntity(Project.class);
|
||||
}
|
||||
catch (FieldAccessException ex) {
|
||||
ClientGraphQlResponse response = ex.getResponse();
|
||||
// ...
|
||||
ClientResponseField field = ex.getField();
|
||||
// ...
|
||||
}
|
||||
include::{include-java}/client/requests/retrieve/Retrieve.java[tag=fieldErrorSync,indent=0]
|
||||
----
|
||||
|
||||
Non-Blocking::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
----
|
||||
Mono<Project> projectMono = graphQlClient.document(document)
|
||||
.retrieve("project")
|
||||
.toEntity(Project.class)
|
||||
.onErrorResume(FieldAccessException.class, ex -> {
|
||||
ClientGraphQlResponse response = ex.getResponse();
|
||||
// ...
|
||||
ClientResponseField field = ex.getField();
|
||||
// ...
|
||||
});
|
||||
include::{include-java}/client/requests/retrieve/Retrieve.java[tag=fieldError,indent=0]
|
||||
----
|
||||
======
|
||||
|
||||
@@ -387,54 +265,20 @@ Sync::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
----
|
||||
ClientGraphQlResponse response = graphQlClient.document(document).executeSync();
|
||||
|
||||
if (!response.isValid()) {
|
||||
// Request failure... <1>
|
||||
}
|
||||
|
||||
ClientResponseField field = response.field("project");
|
||||
if (!field.hasValue()) {
|
||||
if (field.getError() != null) {
|
||||
// Field failure... <2>
|
||||
}
|
||||
else {
|
||||
// Optional field set to null... <3>
|
||||
}
|
||||
}
|
||||
|
||||
Project project = field.toEntity(Project.class); <4>
|
||||
include::{include-java}/client/requests/execute/Execute.java[tag=executeSync,indent=0]
|
||||
----
|
||||
|
||||
Non-Blocking::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
----
|
||||
Mono<Project> projectMono = graphQlClient.document(document)
|
||||
.execute()
|
||||
.map(response -> {
|
||||
if (!response.isValid()) {
|
||||
// Request failure... <1>
|
||||
}
|
||||
|
||||
ClientResponseField field = response.field("project");
|
||||
if (!field.hasValue()) {
|
||||
if (field.getError() != null) {
|
||||
// Field failure... <2>
|
||||
}
|
||||
else {
|
||||
// Optional field set to null... <3>
|
||||
}
|
||||
}
|
||||
|
||||
return field.toEntity(Project.class); <4>
|
||||
});
|
||||
include::{include-java}/client/requests/execute/Execute.java[tag=execute,indent=0]
|
||||
----
|
||||
======
|
||||
|
||||
<1> The response does not have data, only errors
|
||||
<2> Field that is `null` and has an associated error
|
||||
<3> Field that was set to `null` by its `DataFetcher`
|
||||
<2> Field that was set to `null` by its `DataFetcher`
|
||||
<3> Field that is `null` and has an associated error
|
||||
<4> Decode the data at the given path
|
||||
|
||||
|
||||
@@ -468,63 +312,12 @@ You can then:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
Project project = graphQlClient.documentName("projectReleases") <1>
|
||||
.variable("slug", "spring-framework") <2>
|
||||
.retrieveSync()
|
||||
.toEntity(Project.class);
|
||||
include::{include-java}/client/requests/documentsource/DocumentSource.java[tag=documentSource,indent=0]
|
||||
----
|
||||
<1> Load the document from "projectReleases.graphql"
|
||||
<2> Provide variable values.
|
||||
|
||||
|
||||
This approach also works for loading fragments for your queries.
|
||||
Fragments are reusable field selection sets that avoid repetition in a request document.
|
||||
For example, we can use a `...releases` fragment in multiple queries:
|
||||
|
||||
[source,graphql,indent=0,subs="verbatim,quotes"]
|
||||
.src/main/resources/graphql-documents/projectReleases.graphql
|
||||
----
|
||||
query frameworkReleases {
|
||||
project(slug: "spring-framework") {
|
||||
name
|
||||
...releases
|
||||
}
|
||||
}
|
||||
query graphqlReleases {
|
||||
project(slug: "spring-graphql") {
|
||||
name
|
||||
...releases
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
This fragment can be defined in a separate file for reuse:
|
||||
|
||||
[source,graphql,indent=0,subs="verbatim,quotes"]
|
||||
.src/main/resources/graphql-documents/releases.graphql
|
||||
----
|
||||
fragment releases on Project {
|
||||
releases {
|
||||
version
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
You can then send this fragment along the query document:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
Project project = graphQlClient.documentName("projectReleases") <1>
|
||||
.fragmentName("releases") <2>
|
||||
.retrieveSync()
|
||||
.toEntity(Project.class);
|
||||
----
|
||||
<1> Load the document from "projectReleases.graphql"
|
||||
<2> Load the fragment from "releases.graphql" and append it to the document
|
||||
|
||||
|
||||
|
||||
The "JS GraphQL" plugin for IntelliJ supports GraphQL query files with code completion.
|
||||
|
||||
You can use the `GraphQlClient` xref:client.adoc#client.graphqlclient.builder[Builder] to customize the
|
||||
@@ -552,18 +345,13 @@ To start a subscription stream, use `retrieveSubscription` which is similar to
|
||||
xref:client.adoc#client.requests.retrieve[retrieve] for a single response but returning a stream of
|
||||
responses, each decoded to some data:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
Flux<String> greetingFlux = client.document("subscription { greetings }")
|
||||
.retrieveSubscription("greeting")
|
||||
.toEntity(String.class);
|
||||
----
|
||||
include-code::RetrieveSubscription[tag=subscriptionRetrieve,indent=0]
|
||||
|
||||
The `Flux` may terminate with `SubscriptionErrorException` if the subscription ends from
|
||||
the server side with an "error" message. The exception provides access to GraphQL errors
|
||||
decoded from the "error" message.
|
||||
|
||||
The `Flux` may termiate with `GraphQlTransportException` such as
|
||||
The `Flux` may terminate with `GraphQlTransportException` such as
|
||||
`WebSocketDisconnectedException` if the underlying connection is closed or lost. In that
|
||||
case you can use the `retry` operator to restart the subscription.
|
||||
|
||||
@@ -582,29 +370,7 @@ xref:client.adoc#client.subscriptions.retrieve[Retrieve] is only a shortcut to d
|
||||
response map. For more control, use the `executeSubscription` method and handle each
|
||||
response directly:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
Flux<String> greetingFlux = client.document("subscription { greetings }")
|
||||
.executeSubscription()
|
||||
.map(response -> {
|
||||
if (!response.isValid()) {
|
||||
// Request failure...
|
||||
}
|
||||
|
||||
ClientResponseField field = response.field("project");
|
||||
if (!field.hasValue()) {
|
||||
if (field.getError() != null) {
|
||||
// Field failure...
|
||||
}
|
||||
else {
|
||||
// Optional field set to null... <3>
|
||||
}
|
||||
}
|
||||
|
||||
return field.toEntity(String.class)
|
||||
});
|
||||
----
|
||||
|
||||
include-code::ExecuteSubscription[tag=subscriptionExecute,indent=0]
|
||||
|
||||
|
||||
|
||||
@@ -614,52 +380,16 @@ response directly:
|
||||
For blocking transports created with the `GraphQlClient.SyncBuilder`, you create a
|
||||
`SyncGraphQlClientInterceptor` to intercept all requests through the client:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
static class MyInterceptor implements SyncGraphQlClientInterceptor {
|
||||
|
||||
@Override
|
||||
public ClientGraphQlResponse intercept(ClientGraphQlRequest request, Chain chain) {
|
||||
// ...
|
||||
return chain.next(request);
|
||||
}
|
||||
}
|
||||
----
|
||||
include-code::SyncInterceptor[]
|
||||
|
||||
For non-blocking transports created with `GraphQlClient.Builder`, you create a
|
||||
`GraphQlClientInterceptor` to intercept all requests through the client:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
static class MyInterceptor implements GraphQlClientInterceptor {
|
||||
|
||||
@Override
|
||||
public Mono<ClientGraphQlResponse> intercept(ClientGraphQlRequest request, Chain chain) {
|
||||
// ...
|
||||
return chain.next(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<ClientGraphQlResponse> interceptSubscription(ClientGraphQlRequest request, SubscriptionChain chain) {
|
||||
// ...
|
||||
return chain.next(request);
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
include-code::MyInterceptor[]
|
||||
|
||||
Once the interceptor is created, register it through the client builder. For example:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
URI url = ... ;
|
||||
WebSocketClient client = ... ;
|
||||
|
||||
WebSocketGraphQlClient graphQlClient = WebSocketGraphQlClient.builder(url, client)
|
||||
.interceptor(new MyInterceptor())
|
||||
.build();
|
||||
----
|
||||
|
||||
include-code::UseInterceptor[tag=register,indent=0]
|
||||
|
||||
|
||||
|
||||
@@ -697,7 +427,7 @@ You can perform a request as follows:
|
||||
|
||||
List<Book> books = dgsClient.request(new BooksGraphQLQuery()) // <2>
|
||||
.projection(new BooksProjectionRoot<>().id().name()) // <3>
|
||||
.retrieveSync()
|
||||
.retrieveSync("books")
|
||||
.toEntityList(Book.class);
|
||||
----
|
||||
|
||||
|
||||
@@ -74,66 +74,22 @@ GraphQL requests over HTTP, with or without a live server, depending on how
|
||||
To test in Spring WebFlux, without a live server, point to your Spring configuration
|
||||
that declares the GraphQL HTTP endpoint:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
ApplicationContext context = ... ;
|
||||
|
||||
WebTestClient client =
|
||||
WebTestClient.bindToApplicationContext(context)
|
||||
.configureClient()
|
||||
.baseUrl("/graphql")
|
||||
.build();
|
||||
|
||||
HttpGraphQlTester tester = HttpGraphQlTester.create(client);
|
||||
----
|
||||
include-code::HttpSetup[tag=webTestClient,indent=0]
|
||||
|
||||
To test in Spring MVC, without a live server, do the same using `MockMvcWebTestClient`:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
ApplicationContext context = ... ;
|
||||
|
||||
WebTestClient client =
|
||||
MockMvcWebTestClient.bindToApplicationContext(context)
|
||||
.configureClient()
|
||||
.baseUrl("/graphql")
|
||||
.build();
|
||||
|
||||
HttpGraphQlTester tester = HttpGraphQlTester.create(client);
|
||||
----
|
||||
include-code::HttpSetup[tag=mockMvc,indent=0]
|
||||
|
||||
Or to test against a live server running on a port:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
WebTestClient client =
|
||||
WebTestClient.bindToServer()
|
||||
.baseUrl("http://localhost:8080/graphql")
|
||||
.build();
|
||||
|
||||
HttpGraphQlTester tester = HttpGraphQlTester.create(client);
|
||||
----
|
||||
include-code::HttpSetup[tag=liveServer,indent=0]
|
||||
|
||||
Once `HttpGraphQlTester` is created, you can begin to
|
||||
xref:testing.adoc#testing.requests[execute requests] using the same API, independent of the underlying
|
||||
transport. If you need to change any transport specific details, use `mutate()` on an
|
||||
existing `HttpSocketGraphQlTester` to create a new instance with customized settings:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
HttpGraphQlTester tester = HttpGraphQlTester.builder(clientBuilder)
|
||||
.headers(headers -> headers.setBasicAuth("joe", "..."))
|
||||
.build();
|
||||
|
||||
// Use tester...
|
||||
|
||||
HttpGraphQlTester anotherTester = tester.mutate()
|
||||
.headers(headers -> headers.setBasicAuth("peter", "..."))
|
||||
.build();
|
||||
|
||||
// Use anotherTester...
|
||||
|
||||
----
|
||||
include-code::HttpSetup[tag=executeRequests,indent=0]
|
||||
|
||||
|
||||
|
||||
@@ -145,13 +101,7 @@ It is built using the
|
||||
{spring-framework-ref-docs}/web/webflux-websocket.html#webflux-websocket-client[WebSocketClient]
|
||||
from Spring WebFlux and you can create it as follows:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
String url = "http://localhost:8080/graphql";
|
||||
WebSocketClient client = new ReactorNettyWebSocketClient();
|
||||
|
||||
WebSocketGraphQlTester tester = WebSocketGraphQlTester.builder(url, client).build();
|
||||
----
|
||||
include-code::WsSetup[tag=setup,indent=0]
|
||||
|
||||
`WebSocketGraphQlTester` is connection oriented and multiplexed. Each instance establishes
|
||||
its own single, shared connection for all requests. Typically, you'll want to use a single
|
||||
@@ -162,24 +112,7 @@ xref:testing.adoc#testing.requests[execute requests] using the same API, indepen
|
||||
transport. If you need to change any transport specific details, use `mutate()` on an
|
||||
existing `WebSocketGraphQlTester` to create a new instance with customized settings:
|
||||
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
URI url = ... ;
|
||||
WebSocketClient client = ... ;
|
||||
|
||||
WebSocketGraphQlTester tester = WebSocketGraphQlTester.builder(url, client)
|
||||
.headers(headers -> headers.setBasicAuth("joe", "..."))
|
||||
.build();
|
||||
|
||||
// Use tester...
|
||||
|
||||
WebSocketGraphQlTester anotherTester = tester.mutate()
|
||||
.headers(headers -> headers.setBasicAuth("peter", "..."))
|
||||
.build();
|
||||
|
||||
// Use anotherTester...
|
||||
----
|
||||
include-code::WsSetup[tag=customSetup,indent=0]
|
||||
|
||||
`WebSocketGraphQlTester` provides a `stop()` method that you can use to have the WebSocket
|
||||
connection closed, e.g. after a test runs.
|
||||
@@ -192,15 +125,7 @@ connection closed, e.g. after a test runs.
|
||||
`RSocketGraphQlTester` uses `RSocketRequester` from spring-messaging to execute GraphQL
|
||||
requests over RSocket:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
URI uri = URI.create("wss://localhost:8080/rsocket");
|
||||
WebsocketClientTransport transport = WebsocketClientTransport.create(url);
|
||||
|
||||
RSocketGraphQlTester client = RSocketGraphQlTester.builder()
|
||||
.clientTransport(transport)
|
||||
.build();
|
||||
----
|
||||
include-code::RSocketSetup[tag=rsocketSetup,indent=0]
|
||||
|
||||
`RSocketGraphQlTester` is connection oriented and multiplexed. Each instance establishes
|
||||
its own single, shared session for all requests. Typically, you'll want to use a single
|
||||
@@ -219,11 +144,7 @@ Many times it's enough to test GraphQL requests on the server side, without the
|
||||
client to send requests over a transport protocol. To test directly against a
|
||||
`ExecutionGraphQlService`, use the `ExecutionGraphQlServiceTester` extension:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
ExecutionGraphQlService service = ... ;
|
||||
ExecutionGraphQlServiceTester tester = ExecutionGraphQlServiceTester.create(service);
|
||||
----
|
||||
include-code::ServiceSetup[tag=serviceSetup,indent=0]
|
||||
|
||||
Once `ExecutionGraphQlServiceTester` is created, you can begin to
|
||||
xref:testing.adoc#testing.requests[execute requests] using the same API, independent of the underlying
|
||||
@@ -231,13 +152,7 @@ transport.
|
||||
|
||||
`ExecutionGraphQlServiceTester.Builder` provides an option to customize `ExecutionInput` details:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
ExecutionGraphQlService service = ... ;
|
||||
ExecutionGraphQlServiceTester tester = ExecutionGraphQlServiceTester.builder(service)
|
||||
.configureExecutionInput((executionInput, builder) -> builder.executionId(id).build())
|
||||
.build();
|
||||
----
|
||||
include-code::ServiceSetup[tag=customServiceSetup,indent=0]
|
||||
|
||||
|
||||
|
||||
@@ -252,22 +167,11 @@ The `WebGraphQlTester` extension lets you processes request through the
|
||||
`WebGraphQlInterceptor` chain before handing off to `ExecutionGraphQlService` for
|
||||
request execution:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
WebGraphQlHandler handler = ... ;
|
||||
WebGraphQlTester tester = WebGraphQlTester.create(handler);
|
||||
----
|
||||
include-code::WebSetup[tag=webSetup,indent=0]
|
||||
|
||||
The builder for this extension allows you to define HTTP request details:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
WebGraphQlHandler handler = ... ;
|
||||
|
||||
WebGraphQlTester tester = WebGraphQlTester.builder(handler)
|
||||
.headers(headers -> headers.setBasicAuth("joe", "..."))
|
||||
.build();
|
||||
----
|
||||
include-code::WebSetup[tag=customWebSetup,indent=0]
|
||||
|
||||
Once `WebGraphQlTester` is created, you can begin to
|
||||
xref:testing.adoc#testing.requests[execute requests] using the same API, independent of the underlying transport.
|
||||
@@ -297,22 +201,7 @@ Once you have a `GraphQlTester`, you can begin to test requests. The below execu
|
||||
query for a project and uses https://github.com/json-path/JsonPath[JsonPath] to extract
|
||||
project release versions from the response:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
String document = "{" +
|
||||
" project(slug:\"spring-framework\") {" +
|
||||
" releases {" +
|
||||
" version" +
|
||||
" }"+
|
||||
" }" +
|
||||
"}";
|
||||
|
||||
graphQlTester.document(document)
|
||||
.execute()
|
||||
.path("project.releases[*].version")
|
||||
.entityList(String.class)
|
||||
.hasSizeGreaterThan(1);
|
||||
----
|
||||
include-code::TesterRequests[tag=inlineDocument,indent=0]
|
||||
|
||||
The JsonPath is relative to the "data" section of the response.
|
||||
|
||||
@@ -335,18 +224,52 @@ For example, given a file called `projectReleases.graphql` in
|
||||
|
||||
You can then use:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
graphQlTester.documentName("projectReleases") <1>
|
||||
.variable("slug", "spring-framework") <2>
|
||||
.execute()
|
||||
.path("project.releases[*].version")
|
||||
.entityList(String.class)
|
||||
.hasSizeGreaterThan(1);
|
||||
----
|
||||
include-code::TesterRequests[tag=documentName,indent=0]
|
||||
<1> Refer to the document in the file named "project".
|
||||
<2> Set the `slug` variable.
|
||||
|
||||
|
||||
This approach also works for loading fragments for your queries.
|
||||
Fragments are reusable field selection sets that avoid repetition in a request document.
|
||||
For example, we can use a `...releases` fragment in multiple queries:
|
||||
|
||||
[source,graphql,indent=0,subs="verbatim,quotes"]
|
||||
.src/main/resources/graphql-documents/projectReleases.graphql
|
||||
----
|
||||
query frameworkReleases {
|
||||
project(slug: "spring-framework") {
|
||||
name
|
||||
...releases
|
||||
}
|
||||
}
|
||||
query graphqlReleases {
|
||||
project(slug: "spring-graphql") {
|
||||
name
|
||||
...releases
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
This fragment can be defined in a separate file for reuse:
|
||||
|
||||
[source,graphql,indent=0,subs="verbatim,quotes"]
|
||||
.src/main/resources/graphql-documents/releases.graphql
|
||||
----
|
||||
fragment releases on Project {
|
||||
releases {
|
||||
version
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
You can then send this fragment along the query document:
|
||||
|
||||
include-code::TesterRequests[tag=fragment,indent=0]
|
||||
<1> Load the document from "projectReleases.graphql"
|
||||
<2> Load the fragment from "releases.graphql" and append it to the document
|
||||
|
||||
|
||||
[TIP]
|
||||
====
|
||||
The "JS GraphQL" plugin for IntelliJ supports GraphQL query files with code completion.
|
||||
@@ -364,45 +287,24 @@ See xref:testing.adoc#testing.errors[Errors] for more details on error handling.
|
||||
|
||||
|
||||
|
||||
[[testing.requests.nestedPaths]]
|
||||
[[testing.requests.nestedpaths]]
|
||||
=== Nested Paths
|
||||
|
||||
By default, paths are relative to the "data" section of the GraphQL response. You can also
|
||||
nest down to a path, and inspect multiple paths relative to it as follows:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
graphQlTester.document(document)
|
||||
.execute()
|
||||
.path("project", project -> project // <1>
|
||||
.path("name").entity(String.class).isEqualTo("spring-framework")
|
||||
.path("releases[*].version").entityList(String.class).hasSizeGreaterThan(1));
|
||||
----
|
||||
|
||||
include-code::NestedPaths[tag=nestedPaths,indent=0]
|
||||
<1> Use a callback to inspect paths relative to "project".
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[[testing.subscriptions]]
|
||||
== Subscriptions
|
||||
|
||||
To test subscriptions, call `executeSubscription` instead of `execute` to obtain a stream
|
||||
of responses and then use `StepVerifier` from Project Reactor to inspect the stream:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
Flux<String> greetingFlux = tester.document("subscription { greetings }")
|
||||
.executeSubscription()
|
||||
.toFlux("greetings", String.class); // decode at JSONPath
|
||||
|
||||
StepVerifier.create(greetingFlux)
|
||||
.expectNext("Hi")
|
||||
.expectNext("Bonjour")
|
||||
.expectNext("Hola")
|
||||
.verifyComplete();
|
||||
----
|
||||
include-code::TestSubscriptions[tag=testSubscriptions,indent=0]
|
||||
|
||||
Subscriptions are supported only with xref:testing.adoc#testing.websocketgraphqltester[WebSocketGraphQlTester]
|
||||
, or with the server side
|
||||
@@ -417,51 +319,19 @@ When you use `verify()`, any errors under the "errors" key in the response will
|
||||
an assertion failure. To suppress a specific error, use the error filter before
|
||||
`verify()`:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
graphQlTester.query(query)
|
||||
.execute()
|
||||
.errors()
|
||||
.filter(error -> ...)
|
||||
.verify()
|
||||
.path("project.releases[*].version")
|
||||
.entityList(String.class)
|
||||
.hasSizeGreaterThan(1);
|
||||
----
|
||||
|
||||
include-code::TestErrors[tag=verifyErrors,indent=0]
|
||||
|
||||
You can register an error filter at the builder level, to apply to all tests:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
WebGraphQlTester graphQlTester = WebGraphQlTester.builder(client)
|
||||
.errorFilter(error -> ...)
|
||||
.build();
|
||||
----
|
||||
include-code::TestErrors[tag=setupErrorFilter,indent=0]
|
||||
|
||||
If you want to verify that an error does exist, and in contrast to `filter`, throw an
|
||||
assertion error if it doesn't, then use `expect` instead:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
graphQlTester.query(query)
|
||||
.execute()
|
||||
.errors()
|
||||
.expect(error -> ...)
|
||||
.verify()
|
||||
.path("project.releases[*].version")
|
||||
.entityList(String.class)
|
||||
.hasSizeGreaterThan(1);
|
||||
----
|
||||
include-code::TestErrors[tag=expectedErrors,indent=0]
|
||||
|
||||
You can also inspect all errors through a `Consumer`, and doing so also marks them as
|
||||
filtered, so you can then also inspect the data in the response:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
graphQlTester.query(query)
|
||||
.execute()
|
||||
.errors()
|
||||
.satisfy(errors -> {
|
||||
// ...
|
||||
});
|
||||
----
|
||||
include-code::TestErrors[tag=satisfyErrors,indent=0]
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2020-2024 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.graphql.docs.client.httpgraphqlclient;
|
||||
|
||||
import org.springframework.graphql.client.HttpGraphQlClient;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
public class ClientUsage {
|
||||
|
||||
void create() {
|
||||
// tag::create[]
|
||||
WebClient webClient = WebClient.create("https://spring.io/graphql");
|
||||
HttpGraphQlClient graphQlClient = HttpGraphQlClient.create(webClient);
|
||||
// end::create[]
|
||||
}
|
||||
|
||||
void mutateClient() {
|
||||
// tag::mutate[]
|
||||
WebClient webClient = WebClient.create("https://spring.io/graphql");
|
||||
|
||||
HttpGraphQlClient graphQlClient = HttpGraphQlClient.builder(webClient)
|
||||
.headers((headers) -> headers.setBasicAuth("joe", "..."))
|
||||
.build();
|
||||
|
||||
// Perform requests with graphQlClient...
|
||||
|
||||
HttpGraphQlClient anotherGraphQlClient = graphQlClient.mutate()
|
||||
.headers((headers) -> headers.setBasicAuth("peter", "..."))
|
||||
.build();
|
||||
|
||||
// Perform requests with anotherGraphQlClient...
|
||||
// end::mutate[]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2020-2024 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.graphql.docs.client.httpsyncgraphqlclient;
|
||||
|
||||
import org.springframework.graphql.client.HttpSyncGraphQlClient;
|
||||
import org.springframework.web.client.RestClient;
|
||||
|
||||
public class SyncClientUsage {
|
||||
|
||||
void createClient() {
|
||||
// tag::create[]
|
||||
RestClient restClient = RestClient.create("https://spring.io/graphql");
|
||||
HttpSyncGraphQlClient graphQlClient = HttpSyncGraphQlClient.create(restClient);
|
||||
// end::create[]
|
||||
}
|
||||
|
||||
void mutateClient() {
|
||||
// tag::mutate[]
|
||||
RestClient restClient = RestClient.create("https://spring.io/graphql");
|
||||
HttpSyncGraphQlClient graphQlClient = HttpSyncGraphQlClient.builder(restClient)
|
||||
.headers((headers) -> headers.setBasicAuth("joe", "..."))
|
||||
.build();
|
||||
|
||||
// Perform requests with graphQlClient...
|
||||
|
||||
HttpSyncGraphQlClient anotherGraphQlClient = graphQlClient.mutate()
|
||||
.headers((headers) -> headers.setBasicAuth("peter", "..."))
|
||||
.build();
|
||||
|
||||
// Perform requests with anotherGraphQlClient...
|
||||
|
||||
// end::mutate[]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2020-2024 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.graphql.docs.client.interception;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.graphql.client.ClientGraphQlRequest;
|
||||
import org.springframework.graphql.client.ClientGraphQlResponse;
|
||||
import org.springframework.graphql.client.GraphQlClientInterceptor;
|
||||
|
||||
public class MyInterceptor implements GraphQlClientInterceptor {
|
||||
|
||||
@Override
|
||||
public Mono<ClientGraphQlResponse> intercept(ClientGraphQlRequest request, Chain chain) {
|
||||
// ...
|
||||
return chain.next(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<ClientGraphQlResponse> interceptSubscription(ClientGraphQlRequest request, SubscriptionChain chain) {
|
||||
// ...
|
||||
return chain.next(request);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2020-2024 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.graphql.docs.client.interception;
|
||||
|
||||
import org.springframework.graphql.client.ClientGraphQlRequest;
|
||||
import org.springframework.graphql.client.ClientGraphQlResponse;
|
||||
import org.springframework.graphql.client.SyncGraphQlClientInterceptor;
|
||||
|
||||
public class SyncInterceptor implements SyncGraphQlClientInterceptor {
|
||||
|
||||
@Override
|
||||
public ClientGraphQlResponse intercept(ClientGraphQlRequest request, Chain chain) {
|
||||
// ...
|
||||
return chain.next(request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2020-2024 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.graphql.docs.client.interception;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.springframework.graphql.client.WebSocketGraphQlClient;
|
||||
import org.springframework.web.reactive.socket.client.ReactorNettyWebSocketClient;
|
||||
import org.springframework.web.reactive.socket.client.WebSocketClient;
|
||||
|
||||
public class UseInterceptor {
|
||||
|
||||
void registerInterceptor() {
|
||||
// tag::register[]
|
||||
URI url = URI.create("wss://localhost:8080/graphql");
|
||||
WebSocketClient client = new ReactorNettyWebSocketClient();
|
||||
|
||||
WebSocketGraphQlClient graphQlClient = WebSocketGraphQlClient.builder(url, client)
|
||||
.interceptor(new MyInterceptor())
|
||||
.build();
|
||||
// end::register[]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2020-2024 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.graphql.docs.client.requests.documentsource;
|
||||
|
||||
import org.springframework.graphql.client.GraphQlClient;
|
||||
|
||||
public class DocumentSource {
|
||||
|
||||
void documentSource() {
|
||||
GraphQlClient graphQlClient = null;
|
||||
// tag::documentSource[]
|
||||
Project project = graphQlClient.documentName("projectReleases") // <1>
|
||||
.variable("slug", "spring-framework") // <2>
|
||||
.retrieveSync("projectReleases.project")
|
||||
.toEntity(Project.class);
|
||||
// end::documentSource[]
|
||||
}
|
||||
|
||||
record Project() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2020-2024 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.graphql.docs.client.requests.execute;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.graphql.client.ClientGraphQlResponse;
|
||||
import org.springframework.graphql.client.ClientResponseField;
|
||||
import org.springframework.graphql.client.GraphQlClient;
|
||||
|
||||
public class Execute {
|
||||
|
||||
void executeSync() {
|
||||
GraphQlClient graphQlClient = null;
|
||||
String document = "";
|
||||
// tag::executeSync[]
|
||||
ClientGraphQlResponse response = graphQlClient.document(document).executeSync();
|
||||
|
||||
if (!response.isValid()) {
|
||||
// Request failure... <1>
|
||||
}
|
||||
|
||||
ClientResponseField field = response.field("project");
|
||||
if (field.getValue() == null) {
|
||||
if (field.getErrors().isEmpty()) {
|
||||
// Optional field set to null... <2>
|
||||
}
|
||||
else {
|
||||
// Field failure... <3>
|
||||
}
|
||||
}
|
||||
|
||||
Project project = field.toEntity(Project.class); // <4>
|
||||
// end::executeSync[]
|
||||
}
|
||||
|
||||
void execute() {
|
||||
GraphQlClient graphQlClient = null;
|
||||
String document = "";
|
||||
// tag::execute[]
|
||||
Mono<Project> projectMono = graphQlClient.document(document)
|
||||
.execute()
|
||||
.map((response) -> {
|
||||
if (!response.isValid()) {
|
||||
// Request failure... <1>
|
||||
}
|
||||
|
||||
ClientResponseField field = response.field("project");
|
||||
if (field.getValue() == null) {
|
||||
if (field.getErrors().isEmpty()) {
|
||||
// Optional field set to null... <2>
|
||||
}
|
||||
else {
|
||||
// Field failure... <3>
|
||||
}
|
||||
}
|
||||
|
||||
return field.toEntity(Project.class); // <4>
|
||||
});
|
||||
// end::execute[]
|
||||
}
|
||||
|
||||
record Project() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2020-2024 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.graphql.docs.client.requests.retrieve;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.graphql.client.ClientGraphQlResponse;
|
||||
import org.springframework.graphql.client.ClientResponseField;
|
||||
import org.springframework.graphql.client.FieldAccessException;
|
||||
import org.springframework.graphql.client.GraphQlClient;
|
||||
|
||||
public class Retrieve {
|
||||
|
||||
void retrieveSync() {
|
||||
GraphQlClient graphQlClient = null;
|
||||
|
||||
// tag::retrieveSync[]
|
||||
String document =
|
||||
"""
|
||||
{
|
||||
project(slug:"spring-framework") {
|
||||
name
|
||||
releases {
|
||||
version
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
Project project = graphQlClient.document(document) // <1>
|
||||
.retrieveSync("project") // <2>
|
||||
.toEntity(Project.class); // <3>
|
||||
// end::retrieveSync[]
|
||||
}
|
||||
|
||||
void retrieve() {
|
||||
GraphQlClient graphQlClient = null;
|
||||
|
||||
// tag::retrieve[]
|
||||
String document =
|
||||
"""
|
||||
{
|
||||
project(slug:"spring-framework") {
|
||||
name
|
||||
releases {
|
||||
version
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
Mono<Project> project = graphQlClient.document(document) // <1>
|
||||
.retrieve("project") // <2>
|
||||
.toEntity(Project.class); // <3>
|
||||
// end::retrieve[]
|
||||
}
|
||||
|
||||
Project fieldErrorSync() {
|
||||
GraphQlClient graphQlClient = null;
|
||||
String document = "";
|
||||
|
||||
// tag::fieldErrorSync[]
|
||||
try {
|
||||
Project project = graphQlClient.document(document)
|
||||
.retrieveSync("project")
|
||||
.toEntity(Project.class);
|
||||
return project;
|
||||
}
|
||||
catch (FieldAccessException ex) {
|
||||
ClientGraphQlResponse response = ex.getResponse();
|
||||
// ...
|
||||
ClientResponseField field = ex.getField();
|
||||
// return fallback value
|
||||
return new Project();
|
||||
}
|
||||
// end::fieldErrorSync[]
|
||||
}
|
||||
|
||||
void fieldError() {
|
||||
GraphQlClient graphQlClient = null;
|
||||
String document = "";
|
||||
|
||||
// tag::fieldError[]
|
||||
Mono<Project> projectMono = graphQlClient.document(document)
|
||||
.retrieve("project")
|
||||
.toEntity(Project.class)
|
||||
.onErrorResume(FieldAccessException.class, (ex) -> {
|
||||
ClientGraphQlResponse response = ex.getResponse();
|
||||
// ...
|
||||
ClientResponseField field = ex.getField();
|
||||
// return fallback value
|
||||
return Mono.just(new Project());
|
||||
});
|
||||
// end::fieldError[]
|
||||
}
|
||||
|
||||
record Project() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2020-2024 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.graphql.docs.client.rsocketgraphqlclient;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import io.rsocket.transport.netty.client.WebsocketClientTransport;
|
||||
|
||||
import org.springframework.graphql.client.RSocketGraphQlClient;
|
||||
|
||||
public class RSocketClientUsage {
|
||||
|
||||
void create() {
|
||||
// tag::create[]
|
||||
URI uri = URI.create("wss://localhost:8080/rsocket");
|
||||
WebsocketClientTransport transport = WebsocketClientTransport.create(uri);
|
||||
|
||||
RSocketGraphQlClient client = RSocketGraphQlClient.builder()
|
||||
.clientTransport(transport)
|
||||
.build();
|
||||
// end::create[]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2020-2024 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.graphql.docs.client.subscriptions.execute;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import org.springframework.graphql.client.ClientResponseField;
|
||||
import org.springframework.graphql.client.GraphQlClient;
|
||||
|
||||
public class ExecuteSubscription {
|
||||
|
||||
void subscriptionExecute() {
|
||||
GraphQlClient client = null;
|
||||
// tag::subscriptionExecute[]
|
||||
Flux<String> greetingFlux = client.document("subscription { greetings }")
|
||||
.executeSubscription()
|
||||
.map((response) -> {
|
||||
if (!response.isValid()) {
|
||||
// Request failure...
|
||||
}
|
||||
|
||||
ClientResponseField field = response.field("project");
|
||||
if (field.getValue() == null) {
|
||||
if (field.getErrors().isEmpty()) {
|
||||
// Optional field set to null...
|
||||
}
|
||||
else {
|
||||
// Field failure...
|
||||
}
|
||||
}
|
||||
|
||||
return field.toEntity(String.class);
|
||||
});
|
||||
// end::subscriptionExecute[]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2020-2024 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.graphql.docs.client.subscriptions.retrieve;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import org.springframework.graphql.client.GraphQlClient;
|
||||
|
||||
public class RetrieveSubscription {
|
||||
|
||||
void subscriptionRetrieve() {
|
||||
GraphQlClient client = null;
|
||||
// tag::subscriptionRetrieve[]
|
||||
Flux<String> greetingFlux = client.document("subscription { greetings }")
|
||||
.retrieveSubscription("greeting")
|
||||
.toEntity(String.class);
|
||||
// end::subscriptionRetrieve[]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2020-2024 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.graphql.docs.client.websocketgraphqlclient;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.springframework.graphql.client.WebSocketGraphQlClient;
|
||||
import org.springframework.web.reactive.socket.client.ReactorNettyWebSocketClient;
|
||||
import org.springframework.web.reactive.socket.client.WebSocketClient;
|
||||
|
||||
public class WebSocketClientUsage {
|
||||
|
||||
void create() {
|
||||
// tag::create[]
|
||||
String url = "wss://spring.io/graphql";
|
||||
WebSocketClient client = new ReactorNettyWebSocketClient();
|
||||
|
||||
WebSocketGraphQlClient graphQlClient = WebSocketGraphQlClient.builder(url, client).build();
|
||||
// end::create[]
|
||||
}
|
||||
|
||||
void mutate() {
|
||||
// tag::mutate[]
|
||||
String url = "wss://spring.io/graphql";
|
||||
WebSocketClient client = new ReactorNettyWebSocketClient();
|
||||
|
||||
WebSocketGraphQlClient graphQlClient = WebSocketGraphQlClient.builder(url, client)
|
||||
.headers((headers) -> headers.setBasicAuth("joe", "..."))
|
||||
.build();
|
||||
|
||||
// Use graphQlClient...
|
||||
|
||||
WebSocketGraphQlClient anotherGraphQlClient = graphQlClient.mutate()
|
||||
.headers((headers) -> headers.setBasicAuth("peter", "..."))
|
||||
.build();
|
||||
|
||||
// Use anotherGraphQlClient...
|
||||
|
||||
// end::mutate[]
|
||||
}
|
||||
|
||||
void keepAlive() {
|
||||
// tag::keepAlive[]
|
||||
String url = "wss://spring.io/graphql";
|
||||
WebSocketClient client = new ReactorNettyWebSocketClient();
|
||||
|
||||
WebSocketGraphQlClient graphQlClient = WebSocketGraphQlClient.builder(url, client)
|
||||
.keepAlive(Duration.ofSeconds(30))
|
||||
.build();
|
||||
// end::keepAlive[]
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2020-2024 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.graphql.docs.testing.errors;
|
||||
|
||||
import org.springframework.graphql.server.WebGraphQlHandler;
|
||||
import org.springframework.graphql.test.tester.GraphQlTester;
|
||||
import org.springframework.graphql.test.tester.WebGraphQlTester;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TestErrors {
|
||||
|
||||
void verifyErrors() {
|
||||
GraphQlTester graphQlTester = null;
|
||||
String query = "";
|
||||
// tag::verifyErrors[]
|
||||
graphQlTester.document(query)
|
||||
.execute()
|
||||
.errors()
|
||||
.filter((error) -> error.getMessage().equals("ignored error"))
|
||||
.verify()
|
||||
.path("project.releases[*].version")
|
||||
.entityList(String.class)
|
||||
.hasSizeGreaterThan(1);
|
||||
// end::verifyErrors[]
|
||||
}
|
||||
|
||||
void setupErrorFilter() {
|
||||
WebGraphQlHandler handler = null;
|
||||
// tag::setupErrorFilter[]
|
||||
WebGraphQlTester graphQlTester = WebGraphQlTester.builder(handler)
|
||||
.errorFilter((error) -> error.getMessage().equals("ignored error"))
|
||||
.build();
|
||||
// end::setupErrorFilter[]
|
||||
}
|
||||
|
||||
void expectedErrors() {
|
||||
GraphQlTester graphQlTester = null;
|
||||
String query = "";
|
||||
// tag::expectedErrors[]
|
||||
graphQlTester.document(query)
|
||||
.execute()
|
||||
.errors()
|
||||
.expect((error) -> error.getMessage().equals("expected error"))
|
||||
.verify()
|
||||
.path("project.releases[*].version")
|
||||
.entityList(String.class)
|
||||
.hasSizeGreaterThan(1);
|
||||
// end::expectedErrors[]
|
||||
}
|
||||
|
||||
void satisfyErrors() {
|
||||
GraphQlTester graphQlTester = null;
|
||||
String document = "";
|
||||
// tag::satisfyErrors[]
|
||||
graphQlTester.document(document)
|
||||
.execute()
|
||||
.errors()
|
||||
.satisfy((errors) ->
|
||||
assertThat(errors)
|
||||
.anyMatch((error) -> error.getMessage().contains("ignored error"))
|
||||
);
|
||||
// end::satisfyErrors[]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2020-2024 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.graphql.docs.testing.graphqlservicetester;
|
||||
|
||||
import graphql.execution.ExecutionId;
|
||||
|
||||
import org.springframework.graphql.ExecutionGraphQlService;
|
||||
import org.springframework.graphql.test.tester.ExecutionGraphQlServiceTester;
|
||||
|
||||
public class ServiceSetup {
|
||||
|
||||
void serviceSetup() {
|
||||
// tag::serviceSetup[]
|
||||
ExecutionGraphQlService service = /**/ null;
|
||||
ExecutionGraphQlServiceTester tester = ExecutionGraphQlServiceTester.create(service);
|
||||
// end::serviceSetup[]
|
||||
}
|
||||
|
||||
void customServiceSetup() {
|
||||
// tag::customServiceSetup[]
|
||||
ExecutionGraphQlService service = /**/ null;
|
||||
ExecutionId executionId = ExecutionId.generate();
|
||||
ExecutionGraphQlServiceTester tester = ExecutionGraphQlServiceTester.builder(service)
|
||||
.configureExecutionInput((executionInput, builder) -> builder.executionId(executionId).build())
|
||||
.build();
|
||||
// end::customServiceSetup[]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2020-2024 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.graphql.docs.testing.httpgraphqltester;
|
||||
|
||||
import org.springframework.graphql.test.tester.HttpGraphQlTester;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.client.MockMvcWebTestClient;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
|
||||
public class HttpSetup {
|
||||
|
||||
void webTestClient() {
|
||||
// tag::webTestClient[]
|
||||
AnnotationConfigWebApplicationContext context = /**/ new AnnotationConfigWebApplicationContext();
|
||||
|
||||
WebTestClient client =
|
||||
WebTestClient.bindToApplicationContext(context)
|
||||
.configureClient()
|
||||
.baseUrl("/graphql")
|
||||
.build();
|
||||
|
||||
HttpGraphQlTester tester = HttpGraphQlTester.create(client);
|
||||
// end::webTestClient[]
|
||||
}
|
||||
|
||||
void mockMvc() {
|
||||
// tag::mockMvc[]
|
||||
AnnotationConfigWebApplicationContext context = /**/ new AnnotationConfigWebApplicationContext();
|
||||
|
||||
WebTestClient client =
|
||||
MockMvcWebTestClient.bindToApplicationContext(context)
|
||||
.configureClient()
|
||||
.baseUrl("/graphql")
|
||||
.build();
|
||||
|
||||
HttpGraphQlTester tester = HttpGraphQlTester.create(client);
|
||||
// end::mockMvc[]
|
||||
}
|
||||
|
||||
void liveServer() {
|
||||
// tag::liveServer[]
|
||||
WebTestClient client =
|
||||
WebTestClient.bindToServer()
|
||||
.baseUrl("http://localhost:8080/graphql")
|
||||
.build();
|
||||
|
||||
HttpGraphQlTester tester = HttpGraphQlTester.create(client);
|
||||
// end::liveServer[]
|
||||
}
|
||||
|
||||
void executeRequests() {
|
||||
// tag::executeRequests[]
|
||||
WebTestClient.Builder clientBuilder =
|
||||
WebTestClient.bindToServer()
|
||||
.baseUrl("http://localhost:8080/graphql");
|
||||
|
||||
HttpGraphQlTester tester = HttpGraphQlTester.builder(clientBuilder)
|
||||
.headers((headers) -> headers.setBasicAuth("joe", "..."))
|
||||
.build();
|
||||
|
||||
// Use tester...
|
||||
|
||||
HttpGraphQlTester anotherTester = tester.mutate()
|
||||
.headers((headers) -> headers.setBasicAuth("peter", "..."))
|
||||
.build();
|
||||
|
||||
// Use anotherTester...
|
||||
// end::executeRequests[]
|
||||
}
|
||||
|
||||
static class Configuration {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2020-2024 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.graphql.docs.testing.requests;
|
||||
|
||||
import org.springframework.graphql.test.tester.GraphQlTester;
|
||||
|
||||
public class TesterRequests {
|
||||
|
||||
void inlineDocument() {
|
||||
GraphQlTester graphQlTester = null;
|
||||
// tag::inlineDocument[]
|
||||
String document =
|
||||
"""
|
||||
{
|
||||
project(slug:"spring-framework") {
|
||||
releases {
|
||||
version
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
graphQlTester.document(document)
|
||||
.execute()
|
||||
.path("project.releases[*].version")
|
||||
.entityList(String.class)
|
||||
.hasSizeGreaterThan(1);
|
||||
// end::inlineDocument[]
|
||||
}
|
||||
|
||||
void documentName() {
|
||||
GraphQlTester graphQlTester = null;
|
||||
// tag::documentName[]
|
||||
graphQlTester.documentName("projectReleases") // <1>
|
||||
.variable("slug", "spring-framework") // <2>
|
||||
.execute()
|
||||
.path("projectReleases.project.releases[*].version")
|
||||
.entityList(String.class)
|
||||
.hasSizeGreaterThan(1);
|
||||
// end::documentName[]
|
||||
}
|
||||
|
||||
void fragment() {
|
||||
GraphQlTester graphQlTester = null;
|
||||
// tag::fragment[]
|
||||
graphQlTester.documentName("projectReleases") // <1>
|
||||
.fragmentName("releases") // <2>
|
||||
.execute()
|
||||
.path("frameworkReleases.project.releases[*].version")
|
||||
.entityList(String.class)
|
||||
.hasSizeGreaterThan(1);
|
||||
// end::fragment[]
|
||||
}
|
||||
|
||||
record Project() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2020-2024 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.graphql.docs.testing.requests.nestedpaths;
|
||||
|
||||
import org.springframework.graphql.test.tester.GraphQlTester;
|
||||
|
||||
public class NestedPaths {
|
||||
|
||||
void nestedPaths() {
|
||||
GraphQlTester graphQlTester = null;
|
||||
String document = "";
|
||||
// tag::nestedPaths[]
|
||||
graphQlTester.document(document)
|
||||
.execute()
|
||||
.path("project", (project) -> project // <1>
|
||||
.path("name").entity(String.class).isEqualTo("spring-framework")
|
||||
.path("releases[*].version").entityList(String.class).hasSizeGreaterThan(1));
|
||||
// end::nestedPaths[]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2020-2024 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.graphql.docs.testing.rsocketgraphqltester;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import io.rsocket.transport.netty.client.WebsocketClientTransport;
|
||||
|
||||
import org.springframework.graphql.test.tester.RSocketGraphQlTester;
|
||||
|
||||
public class RSocketSetup {
|
||||
|
||||
void rSocketSetup() {
|
||||
// tag::rsocketSetup[]
|
||||
URI url = URI.create("wss://localhost:8080/rsocket");
|
||||
WebsocketClientTransport transport = WebsocketClientTransport.create(url);
|
||||
|
||||
RSocketGraphQlTester client = RSocketGraphQlTester.builder()
|
||||
.clientTransport(transport)
|
||||
.build();
|
||||
// end::rsocketSetup[]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2020-2024 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.graphql.docs.testing.subscriptions;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import org.springframework.graphql.test.tester.GraphQlTester;
|
||||
|
||||
public class TestSubscriptions {
|
||||
|
||||
void testSubscriptions() {
|
||||
GraphQlTester tester = null;
|
||||
// tag::testSubscriptions[]
|
||||
Flux<String> greetingFlux = tester.document("subscription { greetings }")
|
||||
.executeSubscription()
|
||||
.toFlux("greetings", String.class); // decode at JSONPath
|
||||
|
||||
StepVerifier.create(greetingFlux)
|
||||
.expectNext("Hi")
|
||||
.expectNext("Bonjour")
|
||||
.expectNext("Hola")
|
||||
.verifyComplete();
|
||||
// end::testSubscriptions[]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2020-2024 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.graphql.docs.testing.webgraphqltester;
|
||||
|
||||
import org.springframework.graphql.server.WebGraphQlHandler;
|
||||
import org.springframework.graphql.test.tester.WebGraphQlTester;
|
||||
|
||||
public class WebSetup {
|
||||
|
||||
void webSetup() {
|
||||
// tag::webSetup[]
|
||||
WebGraphQlHandler handler = /**/ null;
|
||||
WebGraphQlTester tester = WebGraphQlTester.create(handler);
|
||||
// end::webSetup[]
|
||||
}
|
||||
|
||||
void customWebSetup() {
|
||||
// tag::customWebSetup[]
|
||||
WebGraphQlHandler handler = /**/ null;
|
||||
WebGraphQlTester tester = WebGraphQlTester.builder(handler)
|
||||
.headers((headers) -> headers.setBasicAuth("joe", "..."))
|
||||
.build();
|
||||
// end::customWebSetup[]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2020-2024 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.graphql.docs.testing.websocketgraphqltester;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.springframework.graphql.test.tester.WebSocketGraphQlTester;
|
||||
import org.springframework.web.reactive.socket.client.ReactorNettyWebSocketClient;
|
||||
import org.springframework.web.reactive.socket.client.WebSocketClient;
|
||||
|
||||
public class WsSetup {
|
||||
|
||||
void setup() {
|
||||
// tag::setup[]
|
||||
String url = "http://localhost:8080/graphql";
|
||||
WebSocketClient client = new ReactorNettyWebSocketClient();
|
||||
|
||||
WebSocketGraphQlTester tester = WebSocketGraphQlTester.builder(url, client).build();
|
||||
// end::setup[]
|
||||
}
|
||||
|
||||
void customSetup() {
|
||||
// tag::customSetup[]
|
||||
URI url = URI.create("ws://localhost:8080/graphql");
|
||||
WebSocketClient client = new ReactorNettyWebSocketClient();
|
||||
|
||||
WebSocketGraphQlTester tester = WebSocketGraphQlTester.builder(url, client)
|
||||
.headers((headers) -> headers.setBasicAuth("joe", "..."))
|
||||
.build();
|
||||
|
||||
// Use tester...
|
||||
|
||||
WebSocketGraphQlTester anotherTester = tester.mutate()
|
||||
.headers((headers) -> headers.setBasicAuth("peter", "..."))
|
||||
.build();
|
||||
|
||||
// Use anotherTester...
|
||||
// end::customSetup[]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user