169 lines
4.6 KiB
Plaintext
169 lines
4.6 KiB
Plaintext
[[federation]]
|
|
= Federation
|
|
|
|
Spring for GraphQL provides an integration for the
|
|
https://github.com/apollographql/federation-jvm[federation-jvm] library, which uses
|
|
GraphQL Java to initialize the schema of a sub-graph within a federated graph.
|
|
See https://www.apollographql.com/docs/federation/[Apollo Federation] and the
|
|
https://www.apollographql.com/docs/federation/subgraph-spec[Subgraph spec] for further details.
|
|
|
|
|
|
|
|
[[federation.config]]
|
|
== Config
|
|
|
|
To use the integration, declare a `FederationSchemaFactory` bean in your config, and plug
|
|
it into `GraphQlSource.Builder`. For example, in a Spring Boot application:
|
|
|
|
[source,java,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
@Configuration
|
|
public class FederationConfig {
|
|
|
|
@Bean
|
|
public FederationSchemaFactory schemaFactory() {
|
|
return new FederationSchemaFactory();
|
|
}
|
|
|
|
@Bean
|
|
public GraphQlSourceBuilderCustomizer customizer(FederationSchemaFactory factory) {
|
|
return builder -> builder.schemaFactory(factory::createGraphQLSchema);
|
|
}
|
|
|
|
}
|
|
----
|
|
|
|
Now the schema for the sub-graph service can extend federated types:
|
|
|
|
[source,graphql,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
type Book @key(fields: "id") @extends {
|
|
id: ID! @external
|
|
author: Author
|
|
}
|
|
|
|
type Author {
|
|
id: ID
|
|
firstName: String
|
|
lastName: String
|
|
}
|
|
----
|
|
|
|
|
|
[[federation.entity-mapping]]
|
|
== `@EntityMapping`
|
|
|
|
To resolve federated types in response to the
|
|
https://www.apollographql.com/docs/federation/subgraph-spec/#understanding-query_entities[_entities query],
|
|
you can use `@EntityMapping` methods along with `@SchemaMapping` methods for types under the entity.
|
|
|
|
For example:
|
|
|
|
[source,java,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
@Controller
|
|
private static class BookController {
|
|
|
|
@EntityMapping
|
|
public Book book(@Argument int id) {
|
|
// ...
|
|
}
|
|
|
|
@SchemaMapping
|
|
public Author author(Book book) {
|
|
// ...
|
|
}
|
|
|
|
}
|
|
----
|
|
|
|
The `@Argument` method parameters is resolved from the "representation" input map for
|
|
the entity. You can also inject the full "representation" input `Map`. See
|
|
xref:federation.adoc#federation.entity-mapping.signature[Method Signature] for all
|
|
supported method argument and return value types.
|
|
|
|
You can batch load federated entities by returning a `List` of instances from the controller
|
|
method and accepting a `List` of argument values. In addition, you can use `@BatchMapping`
|
|
methods for subfields.
|
|
|
|
For example:
|
|
|
|
[source,java,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
@Controller
|
|
private static class BookController {
|
|
|
|
@EntityMapping
|
|
public List<Book> book(@Argument List<Integer> idList) {
|
|
// ...
|
|
}
|
|
|
|
@BatchMapping
|
|
public Map<Book, Author> author(List<Book> books) {
|
|
// ...
|
|
}
|
|
}
|
|
----
|
|
|
|
Note `idList` naming convention for the argument, which helps Spring for GraphQL to
|
|
de-pluralize the method parameter name and derive the correct argument name to use.
|
|
Alternatively, set the argument name through the annotation.
|
|
|
|
|
|
|
|
[[federation.entity-mapping.signature]]
|
|
=== Method Signature
|
|
|
|
Entity mapping methods support the following arguments:
|
|
|
|
[cols="1,2"]
|
|
|===
|
|
| Method Argument | Description
|
|
|
|
| `@Argument`
|
|
| For access to a named value from the "representation" input map, also converted to typed Object.
|
|
|
|
| `Map<String, Object>`
|
|
| The full "representation" input map for the entity.
|
|
|
|
| `List<Map<String, Object>>`
|
|
| The list of "representation" input maps when using a single controller method to load
|
|
all entities of a given type.
|
|
|
|
| `@ContextValue`
|
|
| For access to an attribute from the main `GraphQLContext` in `DataFetchingEnvironment`.
|
|
|
|
| `@LocalContextValue`
|
|
| For access to an attribute from the local `GraphQLContext` in `DataFetchingEnvironment`.
|
|
|
|
| `GraphQLContext`
|
|
| For access to the context from the `DataFetchingEnvironment`.
|
|
|
|
| `java.security.Principal`
|
|
| Obtained from the Spring Security context, if available.
|
|
|
|
| `@AuthenticationPrincipal`
|
|
| For access to `Authentication#getPrincipal()` from the Spring Security context.
|
|
|
|
| `DataFetchingFieldSelectionSet`
|
|
| For access to the selection set for the query through the `DataFetchingEnvironment`.
|
|
|
|
| `Locale`, `Optional<Locale>`
|
|
| For access to the `Locale` from the `DataFetchingEnvironment`.
|
|
|
|
| `DataFetchingEnvironment`
|
|
| For direct access to the underlying `DataFetchingEnvironment`.
|
|
|
|
|===
|
|
|
|
`@EntityMapping` methods can return `Mono`, `CompletableFuture`, `Callable`, or the actual entity.
|
|
|
|
|
|
[[federation.entity-mapping.exception-handling]]
|
|
=== Exception Handling
|
|
|
|
You can use `@GraphQlExceptionHandler` methods to map exceptions from `@EntityMapping`
|
|
methods to ``GraphQLError``'s. The errors will be included in the response of the
|
|
"_entities" query. Exception handler methods can be in the same controller or in an
|
|
`@ControllerAdvice` class.
|