Update docs for batch loading

Closes gh-63
This commit is contained in:
Rossen Stoyanchev
2021-09-15 15:52:44 +01:00
parent e24943ac70
commit b021663f5b
2 changed files with 118 additions and 7 deletions

View File

@@ -186,6 +186,39 @@ automatically with the `GraphQlSource.Builder`.
[[boot-graphql-batch-loader-registry]]
== BatchLoaderRegistry
Spring GraphQL supports the GraphQL Java <<execution-batching,batch feature>> and provides
a `BatchLoaderRegistry` to store registrations of batch loading functions. The Boot
starter declares a `BatchLoaderRegistry` bean and configures the `ExecutionGraphQlService`
with it so that applications can simply autowire the registry into their controllers and
register batch loading functions.
For example:
[source,java,indent=0,subs="verbatim,quotes"]
----
@Controller
public class BookController {
public BookController(BatchLoaderRegistry registry) {
registry.forTypePair(Long.class, Author.class).registerBatchLoader((authorIds, env) -> {
// load authors
});
}
@SchemaMapping
public CompletableFuture<Author> author(Book book, DataLoader<Long, Author> loader) {
return loader.load(book.getAuthorId());
}
}
----
[[boot-graphql-graphiql]]
== GraphiQL

View File

@@ -290,6 +290,45 @@ default it is marked as `INTERNAL_ERROR`.
[[execution-batching]]
=== Batching
Given a `Book` and its `Author`, we can create one `DataFetcher` to load books and another
to load the author for each book. This enables queries to select only the data they need,
but when loading multiple books we end up loading the author for each book individually,
which is known as the N+1 select problem.
To address the issue, GraphQL Java provides a
https://www.graphql-java.com/documentation/v16/batching/[batching feature] that allows
related entities, in this case the authors for all books, to be loaded together instead
of individually. Here is an outline of that mechanism:
- At request time, an application can register a batch loading function in the
`DataLoaderRegistry` for each request, that can load instances of a given entity such as
`Author` from a set of unique keys.
- A `DataFetcher` can access the `DataLoader` for the entity and use it to load the
entity by its unique key.
- The `DataLoader` does not load the entity immediately but rather returns a promise, and
defers until it can use the batch loading function to load all related entities together.
- The `DataLoader` also maintains a cache of previously loaded entities.
Spring GraphQL provides the `BatchLoaderRegistry` to store registrations of batch
loading functions. This is given to the `ExecutionGraphQlService` that in turn uses
it to make registrations in the `DataLoaderRegistry` for each request.
A `DataFetcher` can then look up a registered `DataLoader` and use it to load entity
instances, and likewise a controller method can declare a
<<controllers-data-loader,DataLoader argument>> to access the registered loader for the
entity.
The Spring Boot starter declares a
<<boot-graphql-batch-loader-registry,BatchLoaderRegistry bean>>, so that applications can
simply autowire the registry into their controllers in order to register batch loading
functions for entities.
[[data]]
== Data Integration
@@ -512,14 +551,18 @@ Annotated handler methods can choose from one of the following method arguments:
| For access to the source (i.e. parent/container) instance of the field.
See <<controllers-source>>.
| `DataFetchingEnvironment`
| For direct access to the underlying `DataFetchingEnvironment`.
See <<controllers-environment>>.
| `DataLoader`
| For access to a `DataLoader` in the `DataLoaderRegistry`.
See <<controllers-data-loader>>.
| `GraphQLContext`
| For access to the context from the `DataFetchingEnvironment`.
See <<controllers-graphql-context>>.
| `DataFetchingEnvironment`
| For direct access to the underlying `DataFetchingEnvironment`.
See <<controllers-environment>>.
|===
@@ -594,11 +637,39 @@ If the simple name of the Java class matches the GraphQL type, then there is no
explicitly specify the type name in the `@SchemaMapping` annotation.
[[controllers-environment]]
==== `DataFetchingEnvironment`
[[controllers-data-loader]]
==== `DataLoader`
When you register a batch loading function for an entity, as explained in
<<execution-batching>>, you can access the `DataLoader` for the entity by declaring a
method argument of type `DataLoader` and use it to load the entity:
[source,java,indent=0,subs="verbatim,quotes"]
----
@Controller
public class BookController {
public BookController(BatchLoaderRegistry registry) {
registry.forTypePair(Long.class, Author.class).registerBatchLoader((authorIds, env) -> {
// load authors
});
}
@SchemaMapping
public CompletableFuture<Author> author(Book book, DataLoader<Long, Author> loader) {
return loader.load(book.getAuthorId());
}
}
----
By default, `BatchLoaderRegistry` uses the full class name of the value type (e.g. the
class name for `Author`) for the key of the registration, and therefore simply declaring
the `DataLoader` method argument with generic types provides enough information
to locate it in the `DataLoaderRegistry`. As a fallback, the `DataLoader` method argument
resolver will also try the method argument name as the key but typically that should not
be necessary.
To access the `DataFetchingEnvironment` directly, declare a method parameter of the same
type.
[[controllers-graphql-context]]
@@ -608,6 +679,13 @@ To access the `GraphQLContext` from the `DataFetchingEnvironment`, declare a met
parameter of the same type.
[[controllers-environment]]
==== `DataFetchingEnvironment`
To access the `DataFetchingEnvironment` directly, declare a method parameter of the same
type.
[[security]]
== Security