Exempt unresolvable federated entities from checks

Update check ensuring federated types have @EntityMapping
to exempt entities with 'resolvable: false', since by definition
those should not have an @EntityMapping.

See gh-1225

Signed-off-by: Josh Allen <joshuapaulallen@gmail.com>
This commit is contained in:
Josh Allen
2025-05-28 14:23:22 -05:00
committed by rstoyanchev
parent 1f9a21e6ba
commit d3ff9687eb
2 changed files with 28 additions and 6 deletions

View File

@@ -26,6 +26,9 @@ import java.util.stream.Collectors;
import com.apollographql.federation.graphqljava.Federation;
import com.apollographql.federation.graphqljava.SchemaTransformer;
import graphql.language.Argument;
import graphql.language.BooleanValue;
import graphql.language.Directive;
import graphql.language.TypeDefinition;
import graphql.schema.DataFetcher;
import graphql.schema.GraphQLSchema;
@@ -190,12 +193,9 @@ public final class FederationSchemaFactory
private void checkEntityMappings(TypeDefinitionRegistry registry) {
List<String> unmappedEntities = new ArrayList<>();
for (TypeDefinition<?> type : registry.types().values()) {
type.getDirectives().forEach((directive) -> {
boolean isEntityType = directive.getName().equalsIgnoreCase("key");
if (isEntityType && !this.handlerMethods.containsKey(type.getName())) {
unmappedEntities.add(type.getName());
}
});
if (isEntityMappingExpected(type) && !this.handlerMethods.containsKey(type.getName())) {
unmappedEntities.add(type.getName());
}
}
if (!unmappedEntities.isEmpty()) {
throw new IllegalStateException("Unmapped entity types: " +
@@ -203,6 +203,21 @@ public final class FederationSchemaFactory
}
}
/**
* Determine if a handler method is expected for this type: there is at least one '@key' directive
* whose 'resolvable' argument resolves to true (either explicitly, or if the argument is not set).
* @param type the type to inspect.
* @return true if a handler method is expected for this type
*/
private boolean isEntityMappingExpected(TypeDefinition<?> type) {
List<Directive> keyDirectives = type.getDirectives("key");
return !keyDirectives.isEmpty() && keyDirectives.stream()
.anyMatch((keyDirective) -> {
Argument resolvableArg = keyDirective.getArgument("resolvable");
return resolvableArg == null ||
(resolvableArg.getValue() instanceof BooleanValue) && ((BooleanValue) resolvableArg.getValue()).isValue();
});
}
public record EntityMappingInfo(String typeName, HandlerMethod handlerMethod) {

View File

@@ -1,6 +1,9 @@
extend schema @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@extends", "@external"] )
type Book @key(fields: "id") @extends {
id: ID! @external
author: Author
publisher: Publisher
}
type Author {
@@ -8,3 +11,7 @@ type Author {
firstName: String
lastName: String
}
type Publisher @key(fields: "id", resolvable: false) {
id: ID! @external
}