@@ -106,9 +106,14 @@ on an existing `WebSocketGraphQlClient` to create another with different configu
106
106
107
107
----
108
108
109
+
110
+
111
+ [[client-websocketgraphqlclient-connection]]
112
+ ==== Connection
113
+
109
114
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.
112
117
113
118
`WebSocketGraphQlClient` also exposes lifecycle methods:
114
119
@@ -120,12 +125,48 @@ allow requests again.
120
125
121
126
122
127
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
+
123
162
[[client-graphqlclient-builder]]
124
163
=== Builder
125
164
126
165
`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
129
170
130
171
131
172
@@ -193,8 +234,8 @@ response and the field:
193
234
[[client-requests-execute]]
194
235
=== Execute
195
236
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:
198
239
199
240
For example:
200
241
@@ -270,11 +311,22 @@ You can use the `GraphQlClient` <<client-graphqlclient-builder>> to customize th
270
311
271
312
272
313
314
+
273
315
[[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
275
326
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:
278
330
279
331
[source,java,indent=0,subs="verbatim,quotes"]
280
332
----
@@ -283,9 +335,26 @@ obtain a stream of responses, each decoded to a target object:
283
335
.toEntity(String.class);
284
336
----
285
337
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:
289
358
290
359
[source,java,indent=0,subs="verbatim,quotes"]
291
360
----
@@ -310,12 +379,42 @@ For more control over each response, use `executeSubscription`:
310
379
});
311
380
----
312
381
313
- NOTE: Subscriptions are supported only over <<client-websocketgraphqlclient, WebSocket>>.
314
382
315
383
316
384
385
+ [[client-interception]]
386
+ == Interception
317
387
388
+ You create a `GraphQlClientInterceptor` to intercept all requests through a client:
318
389
390
+ [source,java,indent=0,subs="verbatim,quotes"]
391
+ ----
392
+ static class MyInterceptor implements GraphQlClientInterceptor {
319
393
394
+ @Override
395
+ public Mono<ClientGraphQlResponse> intercept(ClientGraphQlRequest request, Chain chain) {
396
+ // ...
397
+ return chain.next(request);
398
+ }
320
399
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
+ ----
321
420
0 commit comments