Add documentation for federation support
Closes gh-864
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
* xref:security.adoc[]
|
||||
* xref:observability.adoc[]
|
||||
* xref:graalvm-native.adoc[]
|
||||
* xref:federation.adoc[]
|
||||
* xref:client.adoc[]
|
||||
* xref:codegen.adoc[]
|
||||
* xref:graphiql.adoc[]
|
||||
|
||||
117
spring-graphql-docs/modules/ROOT/pages/federation.adoc
Normal file
117
spring-graphql-docs/modules/ROOT/pages/federation.adoc
Normal file
@@ -0,0 +1,117 @@
|
||||
[[federation]]
|
||||
= Federation
|
||||
|
||||
Spring for GraphQL provides a small integration layer for the
|
||||
https://github.com/apollographql/federation-jvm[federation-jvm] library that in turn builds
|
||||
on GraphQL Java, and helps to initialize the `graphql.schema.GraphQLSchema` for a GraphQL
|
||||
Java application that is a sub-graph within a federated graph. For more details, see
|
||||
https://www.apollographql.com/docs/federation/[Apollo Federation] and the
|
||||
https://www.apollographql.com/docs/federation/subgraph-spec[Subgraph spec].
|
||||
|
||||
To use the support you can declare a `FederationSchemaFactory` bean in your config, and plug
|
||||
it into `GraphQlSource.Builder`. In a Spring Boot application you can do this through a
|
||||
`GraphQlSourceBuilderCustomizer` as follows:
|
||||
|
||||
[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 your sub-graph schema 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
|
||||
}
|
||||
----
|
||||
|
||||
To assist with resolving federated types as part of an
|
||||
https://www.apollographql.com/docs/federation/subgraph-spec/#understanding-query_entities[_entities]
|
||||
query, you can use `@EntityMapping` methods side by side with `@SchemaMapping` methods
|
||||
for the data that the subgraph application owns. 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 `Map<String, Object>`. The below shows all supported 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.
|
||||
|
||||
| `@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.
|
||||
|
||||
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.
|
||||
|
||||
@@ -67,7 +67,8 @@ locations, e.g. across multiple modules.
|
||||
|
||||
By default, `GraphQlSource.Builder` uses the GraphQL Java `SchemaGenerator` to create the
|
||||
`graphql.schema.GraphQLSchema`. This works for typical use, but if you need to use a
|
||||
different generator, e.g. for federation, you can register a `schemaFactory` callback:
|
||||
different generator, e.g. for xref:federation.adoc[federation], you can register a
|
||||
`schemaFactory` callback:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
|
||||
@@ -155,7 +155,12 @@ public class EntityMappingInvocationTests {
|
||||
|
||||
@Nullable
|
||||
@EntityMapping
|
||||
public Book book(@Argument int id) {
|
||||
public Book book(@Argument int id, Map<String, Object> map) {
|
||||
|
||||
assertThat(map).hasSize(2)
|
||||
.containsEntry("__typename", Book.class.getSimpleName())
|
||||
.containsEntry("id", String.valueOf(id));
|
||||
|
||||
return switch (id) {
|
||||
case -97 -> throw new IllegalArgumentException("handled");
|
||||
case -98 -> throw new IllegalStateException("not handled");
|
||||
|
||||
Reference in New Issue
Block a user