Add reference docs for annotated DataFetcher's

Closes gh-90
This commit is contained in:
Rossen Stoyanchev
2021-08-11 05:23:17 +01:00
parent 020303d0fd
commit 50eef472c5
2 changed files with 243 additions and 26 deletions

View File

@@ -113,30 +113,19 @@ spring.graphql.schema.printer.enabled=false
----
[[boot-graphql-datafetcher]]
== `DataFetcher` Registration
[[boot-graphql-runtimewiring]]
== RuntimeWiring
You can declare `RuntimeWiringConfigurer` beans in your Spring config and use those to
register data fetchers, type resolvers, and more with the GraphQL engine:
The GraphQL Java `RuntimeWiring.Builder` can be used to register ``DataFetcher``s,
type resolvers, custom scalar types, and more. You can declare `RuntimeWiringConfigurer`
beans in your Spring config to get access to the `RuntimeWiring.Builder`. The Boot
starter detects such beans adds them to <<execution-graphqlsource,GraphQlSource.Builder>>.
[source,java,indent=0,subs="verbatim,quotes"]
----
@Component
public class PersonDataWiring implements RuntimeWiringConfigurer {
private final PersonService service;
public PersonDataWiring(PersonService service) {
this.service = service;
}
@Override
public void configure(RuntimeWiring.Builder builder) {
builder.type("Query", wiring ->
wiring.dataFetcher("people", env -> this.service.findAll()));
}
}
----
Typically, however, applications will not implement ``DataFetcher`` directly and will
instead create <<controllers,annotated controllers>>. The Boot
starter declares a `RuntimeWiringConfigurer` called `AnnotatedDataFetcherConfigurer` that
detects `@GraphQlController` classes with annotated handler methods and registers those
as ``DataFetcher``s.
[[boot-repositories-querydsl]]

View File

@@ -188,8 +188,8 @@ support for <<execution-reactive-datafetcher>>, <<execution-context>>, and
=== Reactive `DataFetcher`
The default `GraphQlSource` builder enables support for a `DataFetcher` to return `Mono`
or `Flux`. Both return types are adapted to a `CompletableFuture` with `Flux` values
aggregated and turned into a List, unless the request is a GraphQL subscription request,
or `Flux` which adapts those to a `CompletableFuture` where `Flux` values are aggregated
and turned into a List, unless the request is a GraphQL subscription request,
in which case the return value remains a Reactive Streams `Publisher` for streaming
GraphQL responses.
@@ -316,11 +316,11 @@ Then use it to create a `DataFetcher`:
[source,java,indent=0,subs="verbatim,quotes"]
----
// For single result queries
// For single result queries
DataFetcher<Account> dataFetcher =
QuerydslDataFetcher.builder(repository).single();
// For multi-result queries
// For multi-result queries
DataFetcher<Iterable<Account>> dataFetcher =
QuerydslDataFetcher.builder(repository).many();
----
@@ -367,6 +367,234 @@ Such repositories are auto-detected in the <<boot-repositories-querydsl,Boot sta
[[controllers]]
== Annotated Controllers
Spring GraphQL provides an annotation-based programming model where `@GraphQlController`
components use annotations to declare handler methods with flexible method signatures to
fetch the data for specific GraphQL fields. For example:
[source,java,indent=0,subs="verbatim,quotes"]
----
@GraphQlController
public class GreetingController {
@QueryMapping // <1>
public String hello() { // <2>
return "Hello, world!";
}
}
----
<1> Bind this method to a query, i.e. a field under the Query type.
<2> Determine the query from the method name if not declared on the annotation.
Spring GraphQL uses `RuntimeWiring.Builder` to register the above handler method as a
`graphql.schema.DataFetcher` for the query named "hello".
[[controllers-declaration]]
=== Declaration
You can define `@GraphQlController` beans as standard Spring bean definitions. The
`@GraphQlController` stereotype allows for auto-detection, aligned with Spring general
support for detecting `@Controller` and `@Component` classes on the classpath and
auto-registering bean definitions for them. It also acts as a stereotype for the annotated
class, indicating its role as a data fetching component in a GraphQL application.
`AnnotatedDataFetcherConfigurer` detects `@GraphQlController` beans and registers their
annotated handler methods as ``DataFetcher``s via `RuntimeWiring.Builder`. It is an
implementation of `RuntimeWiringConfigurer` which can be added to `GraphQlSource.Builder`.
The Spring Boot starter automatically declares `AnnotatedDataFetcherConfigurer` as a bean
and adds all `RuntimeWiringConfigurer` beans to `GraphQlSource.Builder` and that enables
support for annotated ``DataFetcher``s, see <<boot-graphql-runtimewiring>>.
[[controllers-mapping]]
=== Mapping
The `@SchemaMapping` annotation maps a handler method to a field in the GraphQL schema
and declares it to be the `DataFetcher` for that field. The annotation can specify the
parent type name, and the field name:
[source,java,indent=0,subs="verbatim,quotes"]
----
@GraphQlController
public class BookController {
@SchemaMapping(typeName="Book", field="author")
public Author getAuthor(Book book) {
// ...
}
}
----
The `@SchemaMapping` annotation can also leave out those attributes, in which case the
field name defaults to the method name, while the type name defaults to the simple class
name of the source/parent object injected into the method. For example, the below
defaults to type "Book" and field "author":
[source,java,indent=0,subs="verbatim,quotes"]
----
@GraphQlController
public class BookController {
@SchemaMapping
public Author author(Book book) {
// ...
}
}
----
The `@SchemaMapping` annotation can be declared at the class level to specify a default
type name for all handler methods in the class.
[source,java,indent=0,subs="verbatim,quotes"]
----
@GraphQlController
@SchemaMapping(typeName="Book")
public class BookController {
// @SchemaMapping methods for fields of the "Book" type
}
----
`@QueryMapping`, `@MutationMapping`, and `@SubscriptionMapping` are meta annotations that
are themselves annotated with `@SchemaMapping` and have the typeName preset to `Query`,
`Mutation`, or `Subscription` respectively. Effectively, these are shortcut annotations
for fields under the Query, Mutation, and Subscription types respectively. For example:
[source,java,indent=0,subs="verbatim,quotes"]
----
@GraphQlController
public class BookController {
@QueryMapping
public Book bookById(@Argument Long id) {
// ...
}
@MutationMapping
public Book addBook(@Argument BookInput bookInput) {
// ...
}
@SubscriptionMapping
public Flux<Book> newPublications() {
// ...
}
}
----
[[controllers-methods]]
=== Handler Methods
`@SchemaMapping` handler methods have flexible signatures and can choose from a range of
method arguments and return values..
[[controllers-arguments]]
==== Method Arguments
Annotated handler methods can choose from one of the following method arguments:
[cols="1,2"]
|===
| Method Argument | Description
| `@Argument`
| For access to field arguments with conversion.
See <<controllers-argument>>.
| Source
| 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>>.
|===
[[controllers-return-values]]
==== Return Values
Annotated handler methods can return any value, including Reactor `Mono` and `Flux` as
described in <<execution-reactive-datafetcher>>.
[[controllers-argument]]
==== `@Argument`
In GraphQL Java, the `DataFetchingEnvironment` provides access to field-specific argument
values. The arguments are available as simple scalar values such as String, or as a `Map`
of values for more complex input, or a `List` of values.
Use `@Argument` to access an argument for the field that maps to the handler method. You
can declare such a method parameter to be of any type. If necessary, Spring GraphQL
converts the value by serializing it to JSON first and then to the target type.
[source,java,indent=0,subs="verbatim,quotes"]
----
@GraphQlController
public class BookController {
@QueryMapping
public Book bookById(@Argument Long id) {
// ...
}
@MutationMapping
public Book addBook(@Argument BookInput bookInput) {
// ...
}
}
----
You can explicitly specify the argument name, for example `@Argument("bookInput")`, or if
it not specified, it defaults to the method parameter name, but this requires the
`-parameters` compiler flag with Java 8+ or debugging information from the compiler.
By default, an `@Argument` is required, but you can make it optional by setting the
`required` flag to false or by declaring the argument with `java.util.Optional`.
[[controllers-source]]
==== Source
In GraphQL Java, the `DataFetchingEnvironment` provides access to the source (i.e.
parent/container) instance of the field. To access this, simply declare a method parameter
of the expected target type.
[source,java,indent=0,subs="verbatim,quotes"]
----
@GraphQlController
public class BookController {
@SchemaMapping
public Author author(Book book) {
// ...
}
}
----
The source method argument also helps to determine the type name for the mapping.
If the simple name of the Java class matches the GraphQL type, then there is no need to
explicitly specify the type name in the `@SchemaMapping` annotation.
[[controllers-environment]]
==== `DataFetchingEnvironment`
To access the `DataFetchingEnvironment` directly, simply declare a method parameter of
the same type.
[[security]]
== Security