Skip to content

Commit 7bfd4fd

Browse files
authored
Better examples of using per request data loaders (#758)
* Better examples of using per request data loaders * Typo
1 parent 21ca1ab commit 7bfd4fd

5 files changed

Lines changed: 84 additions & 3 deletions

File tree

docs/batching.rst

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,40 @@ One thing to note is the above only works if you use `DataLoaderDispatcherInstru
124124
is called. If this was not in place, then all the promises to data will never be dispatched ot the batch loader function
125125
and hence nothing would ever resolve.
126126

127+
Per Request Data Loaders
128+
^^^^^^^^^^^^^^^^^^^^^^^^
129+
130+
If you are serving web requests then the data can be specific to the user requesting it. If you have user specific data then you will not want to
131+
cache data meant for user A to then later give it user B in a subsequent request.
132+
133+
The scope of your DataLoader instances is important. You might want to create them per web request to
134+
ensure data is only cached within that web request and no more.
135+
136+
If your data can be shared across web requests then you might want to scope your data loaders so they survive
137+
longer than the web request say.
138+
139+
But if you are doing per request data loaders then creating a new set of ``GraphQL`` and ``DataLoader`` objects per
140+
request is super cheap. Its the ``GraphQLSchema`` creation that can be expensive, especially if you are using graphql IDL parsing.
141+
142+
Structure your code so that the schema is statically held, perhaps in a static variable or in a singleton IoC component but
143+
build out a new ``GraphQL`` set of objects on each request.
144+
145+
146+
.. code-block:: java
147+
148+
GraphQLSchema staticSchema = staticSchema_Or_MayBeFrom_IoC_Injection();
149+
150+
DataLoaderRegistry registry = new DataLoaderRegistry();
151+
registry.register("character", getCharacterDataLoader());
152+
153+
DataLoaderDispatcherInstrumentation dispatcherInstrumentation
154+
= new DataLoaderDispatcherInstrumentation(registry);
155+
156+
GraphQL graphQL = GraphQL.newGraphQL(staticSchema)
157+
.instrumentation(dispatcherInstrumentation)
158+
.build();
159+
160+
graphQL.execute("{ helloworld }");
161+
162+
// you can now throw away the GraphQL and hence DataLoaderDispatcherInstrumentation
163+
// and DataLoaderRegistry objects since they are really cheap to build per request

src/main/java/graphql/GraphQL.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ public static Builder newGraphQL(GraphQLSchema graphQLSchema) {
140140
* This helps you transform the current GraphQL object into another one by starting a builder with all
141141
* the current values and allows you to transform it how you want.
142142
*
143-
* @param builderConsumer the consumer code that will be given a builder to changee
143+
* @param builderConsumer the consumer code that will be given a builder to transform
144144
*
145145
* @return a new GraphQL object based on calling build on that builder
146146
*/

src/main/java/graphql/schema/GraphQLSchema.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import java.util.List;
1717
import java.util.Map;
1818
import java.util.Set;
19+
import java.util.function.Consumer;
1920

2021
import static graphql.Assert.assertNotNull;
2122
import static graphql.schema.visibility.DefaultGraphqlFieldVisibility.DEFAULT_FIELD_VISIBILITY;
@@ -113,6 +114,20 @@ public boolean isSupportingSubscriptions() {
113114
return subscriptionType != null;
114115
}
115116

117+
/**
118+
* This helps you transform the current GraphQLSchema object into another one by starting a builder with all
119+
* the current values and allows you to transform it how you want.
120+
*
121+
* @param builderConsumer the consumer code that will be given a builder to transform
122+
*
123+
* @return a new GraphQLSchema object based on calling build on that builder
124+
*/
125+
public GraphQLSchema transform(Consumer<Builder> builderConsumer) {
126+
Builder builder = newSchema(this);
127+
builderConsumer.accept(builder);
128+
return builder.build();
129+
}
130+
116131
/**
117132
* @return a new schema builder
118133
*/

src/test/groovy/graphql/schema/GraphQLSchemaTest.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class GraphQLSchemaTest extends Specification {
4040
def existingSchema = TestUtil.schema(idl, runtimeWiring)
4141

4242

43-
GraphQLSchema schema = GraphQLSchema.newSchema(existingSchema).build()
43+
GraphQLSchema schema = existingSchema.transform({})
4444

4545
expect:
4646
assert 0 == runQuery(existingSchema).getErrors().size()

src/test/groovy/readme/BatchingExamples.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public Object get(DataFetchingEnvironment environment) {
7171
// as each level fo the graphql query is executed and hence make batched objects
7272
// available to the query and the associated DataFetchers
7373
//
74-
DataLoaderDispatcherInstrumentation dispatcherInstrumentation
74+
DataLoaderDispatcherInstrumentation dispatcherInstrumentation
7575
= new DataLoaderDispatcherInstrumentation(registry);
7676

7777
//
@@ -85,6 +85,35 @@ public Object get(DataFetchingEnvironment environment) {
8585

8686
}
8787

88+
private void perRequestGraphQl() {
89+
90+
GraphQLSchema staticSchema = staticSchema_Or_MayBeFrom_IoC_Injection();
91+
92+
DataLoaderRegistry registry = new DataLoaderRegistry();
93+
registry.register("character", getCharacterDataLoader());
94+
95+
DataLoaderDispatcherInstrumentation dispatcherInstrumentation
96+
= new DataLoaderDispatcherInstrumentation(registry);
97+
98+
GraphQL graphQL = GraphQL.newGraphQL(staticSchema)
99+
.instrumentation(dispatcherInstrumentation)
100+
.build();
101+
102+
graphQL.execute("{ helloworld }");
103+
104+
// you can now throw away the GraphQL and hence DataLoaderDispatcherInstrumentation
105+
// and DataLoaderRegistry objects since they are really cheap to build per request
106+
107+
}
108+
109+
private GraphQLSchema staticSchema_Or_MayBeFrom_IoC_Injection() {
110+
return null;
111+
}
112+
113+
private DataLoader<?, ?> getCharacterDataLoader() {
114+
return null;
115+
}
116+
88117
private GraphQLSchema buildSchema() {
89118
return null;
90119
}

0 commit comments

Comments
 (0)