diff --git a/graphql-kickstart-spring-support/src/main/java/graphql/kickstart/spring/error/GraphQLErrorFromExceptionHandler.java b/graphql-kickstart-spring-support/src/main/java/graphql/kickstart/spring/error/GraphQLErrorFromExceptionHandler.java index adbc1cb5..c0f5b0d8 100644 --- a/graphql-kickstart-spring-support/src/main/java/graphql/kickstart/spring/error/GraphQLErrorFromExceptionHandler.java +++ b/graphql-kickstart-spring-support/src/main/java/graphql/kickstart/spring/error/GraphQLErrorFromExceptionHandler.java @@ -5,6 +5,7 @@ import graphql.ExceptionWhileDataFetching; import graphql.GraphQLError; import graphql.GraphQLException; +import graphql.GraphqlErrorBuilder; import graphql.SerializationError; import graphql.kickstart.execution.error.DefaultGraphQLErrorHandler; import graphql.kickstart.execution.error.GenericGraphQLError; @@ -33,10 +34,10 @@ protected List filterGraphQLErrors(List errors) { private Collection transform(GraphQLError error) { ErrorContext errorContext = new ErrorContext( - error.getLocations(), - error.getPath(), - error.getExtensions(), - error.getErrorType() + error.getLocations(), + error.getPath(), + error.getExtensions(), + error.getErrorType() ); return extractException(error).map(throwable -> transform(throwable, errorContext)) .orElse(singletonList(new GenericGraphQLError(error.getMessage()))); @@ -60,7 +61,21 @@ private Collection transform(Throwable throwable, ErrorContext err .min(new ThrowableComparator()) .map(applicables::get) .map(factory -> factory.create(throwable, errorContext)) - .orElse(singletonList(new ThrowableGraphQLError(throwable))); + .orElseGet(() -> withThrowable(throwable, errorContext)); + } + + private Collection withThrowable(Throwable throwable, ErrorContext errorContext) { + Map extensions = Optional.ofNullable(errorContext.getExtensions()).orElseGet(HashMap::new); + extensions.put("type", throwable.getClass().getSimpleName()); + return singletonList( + GraphqlErrorBuilder.newError() + .message(throwable.getMessage()) + .errorType(errorContext.getErrorType()) + .locations(errorContext.getLocations()) + .path(errorContext.getPath()) + .extensions(extensions) + .build() + ); } } diff --git a/graphql-spring-boot-autoconfigure/src/test/java/graphql/kickstart/spring/web/boot/GraphQLErrorHandlerTest.java b/graphql-spring-boot-autoconfigure/src/test/java/graphql/kickstart/spring/web/boot/GraphQLErrorHandlerTest.java index fbfac9cc..bec68739 100644 --- a/graphql-spring-boot-autoconfigure/src/test/java/graphql/kickstart/spring/web/boot/GraphQLErrorHandlerTest.java +++ b/graphql-spring-boot-autoconfigure/src/test/java/graphql/kickstart/spring/web/boot/GraphQLErrorHandlerTest.java @@ -40,22 +40,26 @@ public void setUp() { @Test public void illegalArgumentExceptionShouldBeHandledConcretely() { - TestUtils.assertGraphQLError(gql, "query { illegalArgumentException }", - new ThrowableGraphQLError(new IllegalArgumentException("Illegal argument"), "Illegal argument"), - objectMapper); + TestUtils.assertGraphQLError( + gql, + "query { illegalArgumentException }", + new ThrowableGraphQLError(new IllegalArgumentException("Illegal argument"), "Illegal argument"), + objectMapper + ); } @Test public void illegalStateExceptionShouldBeHandledByCatchAll() { TestUtils.assertGraphQLError(gql, "query { illegalStateException }", - new ThrowableGraphQLError(new IllegalStateException("Illegal state"), "Catch all handler"), - objectMapper); + new ThrowableGraphQLError(new IllegalStateException("Illegal state"), "Catch all handler"), + objectMapper); } @Configuration static class BaseConfiguration { public class Query implements GraphQLQueryResolver { + boolean illegalArgumentException() { throw new IllegalArgumentException("Illegal argument"); } @@ -82,9 +86,9 @@ Query queryResolver() { @Bean GraphQLSchema schema() { SchemaParser schemaParser = SchemaParser.newParser() - .file("graphql/error-handler-test.graphql") - .resolvers(queryResolver()) - .build(); + .file("graphql/error-handler-test.graphql") + .resolvers(queryResolver()) + .build(); return schemaParser.makeExecutableSchema(); } } diff --git a/graphql-spring-boot-test/src/main/java/com/graphql/spring/boot/test/TestUtils.java b/graphql-spring-boot-test/src/main/java/com/graphql/spring/boot/test/TestUtils.java index cd4382de..d253c4b6 100644 --- a/graphql-spring-boot-test/src/main/java/com/graphql/spring/boot/test/TestUtils.java +++ b/graphql-spring-boot-test/src/main/java/com/graphql/spring/boot/test/TestUtils.java @@ -10,12 +10,15 @@ import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; @Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) public class TestUtils { - private static ObjectMapper mapper = new ObjectMapper(); + private static final ObjectMapper mapper = new ObjectMapper(); public static Map assertNoGraphQLErrors(GraphQL gql, String query) { return assertNoGraphQLErrors(gql, new HashMap<>(), new Object(), query); @@ -64,7 +67,7 @@ public static void assertGraphQLError(GraphQL gql, String query, GraphQLError er private static String toString(GraphQLError error) { try { - return mapper.writeValueAsString(error); + return mapper.writeValueAsString(error.toSpecification()); } catch (JsonProcessingException e) { log.error("Cannot write error {} as string", error, e); return null;