Skip to content

Commit 4f862c8

Browse files
committed
Added documentation to the deferred results support
1 parent 9850d4f commit 4f862c8

File tree

3 files changed

+233
-0
lines changed

3 files changed

+233
-0
lines changed

docs/defer.rst

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
Deferred Execution
2+
==================
3+
4+
Often when executing a query you have two classes of data. The data you need immediately and the data that could arrive little bit later.
5+
6+
For example imagine this query that gets data on a ``post` and its ``comments`` and ``reviews``.
7+
8+
9+
.. code-block:: graphql
10+
11+
query {
12+
post {
13+
postText
14+
comments {
15+
commentText
16+
}
17+
reviews {
18+
reviewText {
19+
}
20+
}
21+
22+
In this form, you *must* wait for the ``comments`` and ``reviews`` data to be retrieved before you can send the ``post`` data back
23+
to the client. All three data elements are bound to the one query
24+
25+
A naive approach would be to make two queries to gett he most important data first but there is now a better way.
26+
27+
There is ``experimental`` support for deferred execution in graphql-java.
28+
29+
.. code-block:: graphql
30+
31+
query {
32+
post {
33+
postText
34+
comments @defer {
35+
commentText
36+
}
37+
reviews @defer {
38+
reviewText {
39+
}
40+
}
41+
42+
The ``@defer`` directive tells the engine to defer execution of those fields and deliver them later. The rest of the query is executed as
43+
usual. There will be the usual ``ExecutionResult`` of initial data and then a ``org.reactivestreams.Publisher`` of the deferred data.
44+
45+
In the query above, the ``post`` data will be send out in the initial result and then the comments and review data will be sent (in query order)
46+
down a ``Publisher`` later.
47+
48+
The first thing you need to put in place is including the ``defer`` directive into your schema. It wont work without it and graphql-java will
49+
give you an error if you don't.
50+
51+
52+
.. code-block:: java
53+
54+
GraphQLSchema buildSchemaWithDirective() {
55+
56+
GraphQLSchema schema = buildSchema();
57+
schema = schema.transform(builder ->
58+
builder.additionalDirective(Directives.DeferDirective)
59+
);
60+
return schema;
61+
}
62+
63+
64+
Then you execute your query as you would any other graphql query. The deferred results ``Publisher`` will be given to you via
65+
the ``extensions`` map
66+
67+
68+
.. code-block:: java
69+
70+
GraphQLSchema schema = buildSchemaWithDirective();
71+
GraphQL graphQL = GraphQL.newGraphQL(schema).build();
72+
73+
//
74+
// deferredQuery contains the query with @defer directives in it
75+
//
76+
ExecutionResult initialResult = graphQL.execute(ExecutionInput.newExecutionInput().query(deferredQuery).build());
77+
78+
//
79+
// then initial results happen first, the deferred ones will begin AFTER these initial
80+
// results have completed
81+
//
82+
sendResult(httpServletResponse, initialResult);
83+
84+
Map<Object, Object> extensions = initialResult.getExtensions();
85+
Publisher<ExecutionResult> deferredResults = (Publisher<ExecutionResult>) extensions.get("deferredResultStream");
86+
87+
//
88+
// you subscribe to the deferred results like any other reactive stream
89+
//
90+
deferredResults.subscribe(new Subscriber<ExecutionResult>() {
91+
92+
Subscription subscription;
93+
94+
@Override
95+
public void onSubscribe(Subscription s) {
96+
subscription = s;
97+
//
98+
// how many you request is up to you
99+
subscription.request(10);
100+
}
101+
102+
@Override
103+
public void onNext(ExecutionResult executionResult) {
104+
//
105+
// as each deferred result arrives, send it to where it needs to go
106+
//
107+
sendResult(httpServletResponse, executionResult);
108+
subscription.request(10);
109+
}
110+
111+
@Override
112+
public void onError(Throwable t) {
113+
handleError(httpServletResponse, t);
114+
}
115+
116+
@Override
117+
public void onComplete() {
118+
completeResponse(httpServletResponse);
119+
}
120+
});
121+
122+
The above code subscribes to the deferred results and when each one arrives, sends it down to the client.
123+
124+
You can see more details on reactive-streams code here http://www.reactive-streams.org/
125+
126+
``RxJava`` is a popular implementation of reactive-streams. Check out http://reactivex.io/intro.html to find out more
127+
about creating Subscriptions.
128+
129+
graphql-java only produces a stream of deferred results. It does not concern itself with sending these over the network on things
130+
like web sockets and so on. That is important but not a concern of the base graphql-java library. Its up to you
131+
to use whatever network mechanism (websockets / long poll / ....) to get results back to you clients.
132+
133+
Also note that this capability is currently ``experimental`` and not defined by the official ``graphql`` specification. We reserve the
134+
right to change it in a future release or if it enters the official specification. The graphql-java project
135+
is keen to get feedback on this capability.
136+
137+

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ graphql-java is licensed under the MIT License.
5252
mapping
5353
scalars
5454
subscriptions
55+
defer
5556
exceptions
5657
batching
5758
instrumentation
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package readme;
2+
3+
import graphql.Directives;
4+
import graphql.ExecutionInput;
5+
import graphql.ExecutionResult;
6+
import graphql.GraphQL;
7+
import graphql.schema.GraphQLSchema;
8+
import org.reactivestreams.Publisher;
9+
import org.reactivestreams.Subscriber;
10+
import org.reactivestreams.Subscription;
11+
12+
import javax.servlet.http.HttpServletResponse;
13+
import java.util.Map;
14+
15+
@SuppressWarnings({"unused", "ConstantConditions", "UnusedAssignment", "unchecked"})
16+
public class DeferredExamples {
17+
18+
GraphQLSchema buildSchemaWithDirective() {
19+
20+
GraphQLSchema schema = buildSchema();
21+
schema = schema.transform(builder ->
22+
builder.additionalDirective(Directives.DeferDirective)
23+
);
24+
return schema;
25+
}
26+
27+
void basicExample(HttpServletResponse httpServletResponse, String deferredQuery) {
28+
GraphQLSchema schema = buildSchemaWithDirective();
29+
GraphQL graphQL = GraphQL.newGraphQL(schema).build();
30+
31+
//
32+
// deferredQuery contains the query with @defer directives in it
33+
//
34+
ExecutionResult initialResult = graphQL.execute(ExecutionInput.newExecutionInput().query(deferredQuery).build());
35+
36+
//
37+
// then initial results happen first, the deferred ones will begin AFTER these initial
38+
// results have completed
39+
//
40+
sendResult(httpServletResponse, initialResult);
41+
42+
Map<Object, Object> extensions = initialResult.getExtensions();
43+
Publisher<ExecutionResult> deferredResults = (Publisher<ExecutionResult>) extensions.get("deferredResultStream");
44+
45+
//
46+
// you subscribe to the deferred results like any other reactive stream
47+
//
48+
deferredResults.subscribe(new Subscriber<ExecutionResult>() {
49+
50+
Subscription subscription;
51+
52+
@Override
53+
public void onSubscribe(Subscription s) {
54+
subscription = s;
55+
//
56+
// how many you request is up to you
57+
subscription.request(10);
58+
}
59+
60+
@Override
61+
public void onNext(ExecutionResult executionResult) {
62+
//
63+
// as each deferred result arrives, send it to where it needs to go
64+
//
65+
sendResult(httpServletResponse, executionResult);
66+
subscription.request(10);
67+
}
68+
69+
@Override
70+
public void onError(Throwable t) {
71+
handleError(httpServletResponse, t);
72+
}
73+
74+
@Override
75+
public void onComplete() {
76+
completeResponse(httpServletResponse);
77+
}
78+
});
79+
}
80+
81+
private void completeResponse(HttpServletResponse httpServletResponse) {
82+
}
83+
84+
private void handleError(HttpServletResponse httpServletResponse, Throwable t) {
85+
}
86+
87+
private void sendResult(HttpServletResponse httpServletResponse, ExecutionResult initialResult) {
88+
}
89+
90+
91+
private GraphQLSchema buildSchema() {
92+
return null;
93+
}
94+
95+
}

0 commit comments

Comments
 (0)