Skip to content

Commit

Permalink
FederationSchemaFactory checks for unmapped entities
Browse files Browse the repository at this point in the history
Closes gh-1088
  • Loading branch information
rstoyanchev committed Feb 20, 2025
1 parent 310424e commit 2f1c4b1
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -25,6 +25,7 @@

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;
Expand Down Expand Up @@ -177,12 +178,23 @@ public GraphQLSchema createGraphQLSchema(TypeDefinitionRegistry registry, Runtim
* @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) {

Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -52,6 +52,7 @@
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.
Expand Down Expand Up @@ -175,6 +176,18 @@ void batchingWithoutResult(Class<?> controllerClass) {
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);
Expand Down Expand Up @@ -299,6 +312,13 @@ public GraphQLError handle(IllegalArgumentException ex, DataFetchingEnvironment
}


@SuppressWarnings("unused")
@Controller
private static class EmptyController {

}


private static class BookBatchService {

public List<Book> book(List<Integer> idList, List<Map<String, Object>> representations) {
Expand Down

0 comments on commit 2f1c4b1

Please sign in to comment.