FederationSchemaFactory checks for unmapped entities
Closes gh-1088
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,6 +25,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
import com.apollographql.federation.graphqljava.Federation;
|
||||
import com.apollographql.federation.graphqljava.SchemaTransformer;
|
||||
import graphql.language.TypeDefinition;
|
||||
import graphql.schema.DataFetcher;
|
||||
import graphql.schema.GraphQLSchema;
|
||||
import graphql.schema.TypeResolver;
|
||||
@@ -177,12 +178,23 @@ public final class FederationSchemaFactory
|
||||
* @param wiring the existing runtime wiring
|
||||
*/
|
||||
public SchemaTransformer createSchemaTransformer(TypeDefinitionRegistry registry, RuntimeWiring wiring) {
|
||||
checkEntityMappings(registry);
|
||||
Assert.state(this.typeResolver != null, "afterPropertiesSet not called");
|
||||
return Federation.transform(registry, wiring)
|
||||
.fetchEntities(new EntitiesDataFetcher(this.handlerMethods, getExceptionResolver()))
|
||||
.resolveEntityType(this.typeResolver);
|
||||
}
|
||||
|
||||
private void checkEntityMappings(TypeDefinitionRegistry registry) {
|
||||
for (TypeDefinition<?> type : registry.types().values()) {
|
||||
type.getDirectives().forEach((directive) -> {
|
||||
boolean isEntityType = directive.getName().equalsIgnoreCase("key");
|
||||
Assert.state(!isEntityType || this.handlerMethods.containsKey(type.getName()),
|
||||
"No EntityMapping method for federated type: '" + type.getName() + "'");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public record EntityMappingInfo(String typeName, HandlerMethod handlerMethod) {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -52,6 +52,7 @@ import org.springframework.lang.Nullable;
|
||||
import org.springframework.stereotype.Controller;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
|
||||
/**
|
||||
* Tests for requests handled through {@code @EntityMapping} methods.
|
||||
@@ -175,6 +176,18 @@ public class EntityMappingInvocationTests {
|
||||
assertError(helper, 2, "INTERNAL_ERROR", "Entity fetcher returned null or completed empty");
|
||||
}
|
||||
|
||||
@Test
|
||||
void unmappedEntity() {
|
||||
Map<String, Object> variables =
|
||||
Map.of("representations", List.of(
|
||||
Map.of("__typename", "Book", "id", "-99"),
|
||||
Map.of("__typename", "Book", "id", "4"),
|
||||
Map.of("__typename", "Book", "id", "5")));
|
||||
|
||||
assertThatIllegalStateException().isThrownBy(() -> executeWith(EmptyController.class, variables))
|
||||
.withMessage("No EntityMapping method for federated type: 'Book'");
|
||||
}
|
||||
|
||||
private static ResponseHelper executeWith(Class<?> controllerClass, Map<String, Object> variables) {
|
||||
ExecutionGraphQlRequest request = TestExecutionRequest.forDocumentAndVars(document, variables);
|
||||
Mono<ExecutionGraphQlResponse> responseMono = graphQlService(controllerClass).execute(request);
|
||||
@@ -299,6 +312,13 @@ public class EntityMappingInvocationTests {
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Controller
|
||||
private static class EmptyController {
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static class BookBatchService {
|
||||
|
||||
public List<Book> book(List<Integer> idList, List<Map<String, Object>> representations) {
|
||||
|
||||
Reference in New Issue
Block a user