Skip to content

Commit bb62808

Browse files
committed
Update documentation for client interception
See gh-322
1 parent f54ee52 commit bb62808

File tree

3 files changed

+116
-17
lines changed

3 files changed

+116
-17
lines changed

spring-graphql-docs/src/docs/asciidoc/client.adoc

Lines changed: 112 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,14 @@ on an existing `WebSocketGraphQlClient` to create another with different configu
106106
107107
----
108108

109+
110+
111+
[[client-websocketgraphqlclient-connection]]
112+
==== Connection
113+
109114
A connection is established transparently when requests are made. There is only one
110-
shared, active connection at a time. If the connection is lost, it is automatically
111-
re-established on the next request.
115+
shared, active connection at a time. If the connection is lost, it is re-established on
116+
the next request.
112117

113118
`WebSocketGraphQlClient` also exposes lifecycle methods:
114119

@@ -120,12 +125,48 @@ allow requests again.
120125

121126

122127

128+
[[client-websocketgraphqlclient-interceptor]]
129+
==== Interceptor
130+
131+
The https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md[GraphQL over WebSocket]
132+
protocol defines a number of connection oriented messages in addition to executing
133+
requests. For example, a client sends `"connection_init"` and the server responds with
134+
`"connection_ack"` at the start of a connection.
135+
136+
For WebSocket transport specific interception, you can create a
137+
`WebSocketGraphQlClientInterceptor`:
138+
139+
[source,java,indent=0,subs="verbatim,quotes"]
140+
----
141+
static class MyInterceptor implements WebSocketGraphQlClientInterceptor {
142+
143+
@Override
144+
public Mono<Object> connectionInitPayload() {
145+
// ... the "connection_init" payload to send
146+
}
147+
148+
@Override
149+
public Mono<Void> handleConnectionAck(Map<String, Object> ackPayload) {
150+
// ... the "connection_ack" payload received
151+
}
152+
153+
}
154+
----
155+
156+
<<client-interception,Register>> the above interceptor as any other
157+
`GraphQlClientInterceptor` and use it also to intercept GraphQL requests, but note there
158+
can be at most one interceptor of type `WebSocketGraphQlClientInterceptor`.
159+
160+
161+
123162
[[client-graphqlclient-builder]]
124163
=== Builder
125164

126165
`GraphQlClient` defines a parent `Builder` with common configuration options for the
127-
builders of all extensions. Currently, it has lets you configure a `DocumentSource`,
128-
which is a strategy for loading the document for a request by file name.
166+
builders of all extensions. Currently, it has lets you configure:
167+
168+
- `DocumentSource` strategy to load the document for a request from a file
169+
- <<client-interception>> of executed requests
129170

130171

131172

@@ -193,8 +234,8 @@ response and the field:
193234
[[client-requests-execute]]
194235
=== Execute
195236

196-
`retrieve` is only a shortcut to decode from a single path in the response map. For more
197-
control, use the `execute` method and handle the response:
237+
<<client-requests-retrieve>> is only a shortcut to decode from a single path in the
238+
response map. For more control, use the `execute` method and handle the response:
198239

199240
For example:
200241

@@ -270,11 +311,22 @@ You can use the `GraphQlClient` <<client-graphqlclient-builder>> to customize th
270311

271312

272313

314+
273315
[[client-subscriptions]]
274-
== Subscriptions
316+
== Subscription Requests
317+
318+
`GraphQlClient` can execute subscriptions over transports that support it. Currently, only
319+
the WebSocket transport supports GraphQL streams, so you'll need to create a
320+
<<client-websocketgraphqlclient,WebSocketGraphQlClient>>.
321+
322+
323+
324+
[[client-subscriptions-retrieve]]
325+
=== Retrieve
275326

276-
For a subscription operation, call `retrieveSubscription` instead of `retrieve` to
277-
obtain a stream of responses, each decoded to a target object:
327+
To start a subscription stream, use `retrieveSubscription` which is similar to
328+
<<client-requests-retrieve,retrieve>> for a single response but returning a stream of
329+
responses, each decoded to some data:
278330

279331
[source,java,indent=0,subs="verbatim,quotes"]
280332
----
@@ -283,9 +335,26 @@ obtain a stream of responses, each decoded to a target object:
283335
.toEntity(String.class);
284336
----
285337

286-
Similar to the <<client-requests-retrieve, retrieve>> vs <<client-requests-execute, execute>>
287-
alternatives for single response requests, the same is also available for subscriptions.
288-
For more control over each response, use `executeSubscription`:
338+
A subscription stream may end with:
339+
340+
- `SubscriptionErrorException` if the server ends the
341+
subscription with an explicit "error" message that contains one or more GraphQL errors.
342+
The exception provides access to the GraphQL errors decoded from that message.
343+
- `GraphQlTransportException` such as `WebSocketDisconnectedException` if the underlying
344+
connection is closed or lost in which case you can use the `retry` operator to reestablish
345+
the connection and start the subscription again.
346+
347+
348+
349+
350+
351+
352+
[[client-subscriptions-execute]]
353+
=== Execute
354+
355+
<<client-subscriptions-retrieve>> is only a shortcut to decode from a single path in each
356+
response map. For more control, use the `executeSubscription` method and handle each
357+
response directly:
289358

290359
[source,java,indent=0,subs="verbatim,quotes"]
291360
----
@@ -310,12 +379,42 @@ For more control over each response, use `executeSubscription`:
310379
});
311380
----
312381

313-
NOTE: Subscriptions are supported only over <<client-websocketgraphqlclient, WebSocket>>.
314382

315383

316384

385+
[[client-interception]]
386+
== Interception
317387

388+
You create a `GraphQlClientInterceptor` to intercept all requests through a client:
318389

390+
[source,java,indent=0,subs="verbatim,quotes"]
391+
----
392+
static class MyInterceptor implements GraphQlClientInterceptor {
319393
394+
@Override
395+
public Mono<ClientGraphQlResponse> intercept(ClientGraphQlRequest request, Chain chain) {
396+
// ...
397+
return chain.next(request);
398+
}
320399
400+
@Override
401+
public Flux<ClientGraphQlResponse> interceptSubscription(ClientGraphQlRequest request, SubscriptionChain chain) {
402+
// ...
403+
return chain.next(request);
404+
}
405+
406+
}
407+
----
408+
409+
Once the interceptor is created, register it through the client builder:
410+
411+
[source,java,indent=0,subs="verbatim,quotes"]
412+
----
413+
URI url = ... ;
414+
WebSocketClient client = ... ;
415+
416+
WebSocketGraphQlClient graphQlClient = WebSocketGraphQlClient.builder(url, client)
417+
.interceptor(new MyInterceptor())
418+
.build();
419+
----
321420

spring-graphql/src/main/java/org/springframework/graphql/client/GraphQlClient.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,8 +197,8 @@ interface RequestSpec {
197197
* <ul>
198198
* <li>Completes if the subscription completes before the connection is closed.
199199
* <li>{@link SubscriptionErrorException} if the subscription ends with an error.
200-
* <li>{@link IllegalStateException} if the connection is closed or lost
201-
* before the stream terminates.
200+
* <li>{@link WebSocketDisconnectedException} if the connection is closed or
201+
* lost before the stream terminates.
202202
* <li>Exception for connection and GraphQL session initialization issues.
203203
* </ul>
204204
* <p>The {@code Flux} may be cancelled to notify the server to end the

spring-graphql/src/main/java/org/springframework/graphql/client/GraphQlTransport.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ public interface GraphQlTransport {
5050
* <ul>
5151
* <li>Completes if the subscription completes before the connection is closed.
5252
* <li>{@link SubscriptionErrorException} if the subscription ends with an error.
53-
* <li>{@link IllegalStateException} if the connection is closed or lost
54-
* before the stream terminates.
53+
* <li>{@link WebSocketDisconnectedException} if the connection is closed or
54+
* lost before the stream terminates.
5555
* <li>Exception for connection and GraphQL session initialization issues.
5656
* </ul>
5757
* <p>The {@code Flux} may be cancelled to notify the server to end the

0 commit comments

Comments
 (0)