Add hook for the inspection of schema mappings
Closes gh-672
This commit is contained in:
@@ -417,18 +417,30 @@ implement this interface. That includes those for <<controllers>>, and those for
|
||||
controllers, the return type is derived from the declared return type on a
|
||||
`@SchemaMapping` method.
|
||||
|
||||
On startup, Spring for GraphQL inspects all schema fields, `DataFetcher` registrations,
|
||||
On startup, Spring for GraphQL can inspect schema fields, `DataFetcher` registrations,
|
||||
and the properties of Java objects returned from `DataFetcher` implementations to check
|
||||
if all schema fields are covered either by an explicitly registered `DataFetcher`, or
|
||||
a matching Java object property. The inspection also performs a reverse check looking for
|
||||
`DataFetcher` registrations against schema fields that don't exist. This inspection is
|
||||
performed automatically, and results in a report that is logged at INFO level on startup.
|
||||
For example:
|
||||
`DataFetcher` registrations against schema fields that don't exist.
|
||||
|
||||
To enable inspection of schema mappings:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
GraphQlSource.Builder builder = ...
|
||||
|
||||
builder.schemaResources(..)
|
||||
.inspectSchemaMappings(report -> {
|
||||
logger.debug(report);
|
||||
})
|
||||
----
|
||||
|
||||
Below is an example report:
|
||||
|
||||
----
|
||||
GraphQL schema inspection:
|
||||
Unmapped fields: {Book=[title], Author[firstName, lastName]} // <1>
|
||||
Unmapped DataFetcher registrations: {Book.reviews=BookController#reviews[1 args]} <2>
|
||||
Unmapped registrations: {Book.reviews=BookController#reviews[1 args]} <2>
|
||||
Skipped types: [BookOrAuthor] // <3>
|
||||
----
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import graphql.language.InterfaceTypeDefinition;
|
||||
@@ -71,6 +72,9 @@ final class DefaultSchemaResourceGraphQlSourceBuilder
|
||||
@Nullable
|
||||
private BiFunction<TypeDefinitionRegistry, RuntimeWiring, GraphQLSchema> schemaFactory;
|
||||
|
||||
@Nullable
|
||||
private Consumer<SchemaReport> schemaReportConsumer;
|
||||
|
||||
|
||||
@Override
|
||||
public DefaultSchemaResourceGraphQlSourceBuilder schemaResources(Resource... resources) {
|
||||
@@ -96,6 +100,12 @@ final class DefaultSchemaResourceGraphQlSourceBuilder
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphQlSource.SchemaResourceBuilder inspectSchemaMappings(Consumer<SchemaReport> consumer) {
|
||||
this.schemaReportConsumer = consumer;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultSchemaResourceGraphQlSourceBuilder schemaFactory(
|
||||
BiFunction<TypeDefinitionRegistry, RuntimeWiring, GraphQLSchema> schemaFactory) {
|
||||
@@ -136,11 +146,13 @@ final class DefaultSchemaResourceGraphQlSourceBuilder
|
||||
// SchemaMappingInspector needs RuntimeWiring, but cannot run here since type
|
||||
// visitors may transform the schema, for example to add Connection types.
|
||||
|
||||
configureGraphQl(builder -> {
|
||||
GraphQLSchema schema = builder.build().getGraphQLSchema();
|
||||
SchemaReport report = SchemaMappingInspector.inspect(schema, runtimeWiring);
|
||||
logger.info(report);
|
||||
});
|
||||
if (this.schemaReportConsumer != null) {
|
||||
configureGraphQl(builder -> {
|
||||
GraphQLSchema schema = builder.build().getGraphQLSchema();
|
||||
SchemaReport report = SchemaMappingInspector.inspect(schema, runtimeWiring);
|
||||
this.schemaReportConsumer.accept(report);
|
||||
});
|
||||
}
|
||||
|
||||
return (this.schemaFactory != null ?
|
||||
this.schemaFactory.apply(registry, runtimeWiring) :
|
||||
|
||||
@@ -19,7 +19,6 @@ package org.springframework.graphql.execution;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import graphql.GraphQL;
|
||||
import graphql.execution.instrumentation.Instrumentation;
|
||||
@@ -201,6 +200,16 @@ public interface GraphQlSource {
|
||||
*/
|
||||
SchemaResourceBuilder defaultTypeResolver(TypeResolver typeResolver);
|
||||
|
||||
/**
|
||||
* Enable inspection of schema mappings to find unmapped fields and
|
||||
* unmapped {@code DataFetcher} registrations. For more details, see
|
||||
* {@link SchemaReport} and the reference documentation.
|
||||
* @param reportConsumer a hook to inspect the report
|
||||
* @return the current builder
|
||||
* @since 1.2.0
|
||||
*/
|
||||
SchemaResourceBuilder inspectSchemaMappings(Consumer<SchemaReport> reportConsumer);
|
||||
|
||||
/**
|
||||
* Configure a function to create the {@link GraphQLSchema} from the
|
||||
* given {@link TypeDefinitionRegistry} and {@link RuntimeWiring}.
|
||||
|
||||
Reference in New Issue
Block a user