From 1151d254679311a83672be500604bd12b1437e55 Mon Sep 17 00:00:00 2001 From: Robert Reta Date: Tue, 22 Nov 2022 14:29:12 -0600 Subject: [PATCH 1/2] When an exception was thrown from a dataloader, it would be wrapped in a CompletionException and not accounted for in the exception handler. --- .../DefaultDataFetcherExceptionHandler.kt | 7 ++++++- .../DefaultDataFetcherExceptionHandlerTest.kt | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/exceptions/DefaultDataFetcherExceptionHandler.kt b/graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/exceptions/DefaultDataFetcherExceptionHandler.kt index fea1431ec..c61658736 100644 --- a/graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/exceptions/DefaultDataFetcherExceptionHandler.kt +++ b/graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/exceptions/DefaultDataFetcherExceptionHandler.kt @@ -24,6 +24,7 @@ import org.slf4j.Logger import org.slf4j.LoggerFactory import org.springframework.util.ClassUtils import java.util.concurrent.CompletableFuture +import java.util.concurrent.CompletionException /** * Default DataFetcherExceptionHandler used by the framework, can be replaced with a custom implementation. @@ -41,7 +42,7 @@ class DefaultDataFetcherExceptionHandler : DataFetcherExceptionHandler { } private fun doHandleException(handlerParameters: DataFetcherExceptionHandlerParameters): DataFetcherExceptionHandlerResult { - val exception = handlerParameters.exception + val exception = unwrapCompletionException(handlerParameters.exception) logger.error( "Exception while executing data fetcher for ${handlerParameters.path}: ${exception.message}", exception @@ -62,6 +63,10 @@ class DefaultDataFetcherExceptionHandler : DataFetcherExceptionHandler { .build() } + private fun unwrapCompletionException(e: Throwable): Throwable { + return if(e is CompletionException && e.cause != null) e.cause!! else e + } + companion object { private val logger: Logger = LoggerFactory.getLogger(DefaultDataFetcherExceptionHandler::class.java) diff --git a/graphql-dgs/src/test/kotlin/com/netflix/graphql/dgs/exceptions/DefaultDataFetcherExceptionHandlerTest.kt b/graphql-dgs/src/test/kotlin/com/netflix/graphql/dgs/exceptions/DefaultDataFetcherExceptionHandlerTest.kt index 970b55f9b..fa9e320a6 100644 --- a/graphql-dgs/src/test/kotlin/com/netflix/graphql/dgs/exceptions/DefaultDataFetcherExceptionHandlerTest.kt +++ b/graphql-dgs/src/test/kotlin/com/netflix/graphql/dgs/exceptions/DefaultDataFetcherExceptionHandlerTest.kt @@ -26,6 +26,7 @@ import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.springframework.security.access.AccessDeniedException +import java.util.concurrent.CompletionException internal class DefaultDataFetcherExceptionHandlerTest { @@ -126,4 +127,20 @@ internal class DefaultDataFetcherExceptionHandlerTest { // We return null here because we don't want graphql-java to write classification field assertThat(result.errors[0].errorType).isNull() } + + @Test + fun `CompletionException returns wrapped error code`() { + val completionException = CompletionException("com.netflix.graphql.dgs.exceptions.DgsEntityNotFoundException: Requested entity not found", + DgsEntityNotFoundException()) + every { dataFetcherExceptionHandlerParameters.exception }.returns(completionException) + + val result = DefaultDataFetcherExceptionHandler().handleException(dataFetcherExceptionHandlerParameters).get() + assertThat(result.errors.size).isEqualTo(1) + + val extensions = result.errors[0].extensions + assertThat(extensions["errorType"]).isEqualTo("NOT_FOUND") + + // We return null here because we don't want graphql-java to write classification field + assertThat(result.errors[0].errorType).isNull() + } } From b57c162ab3f303e563743ba2749e94953051828a Mon Sep 17 00:00:00 2001 From: Robert Reta Date: Tue, 22 Nov 2022 14:50:12 -0600 Subject: [PATCH 2/2] Formatting kotlin --- .../dgs/exceptions/DefaultDataFetcherExceptionHandler.kt | 2 +- .../exceptions/DefaultDataFetcherExceptionHandlerTest.kt | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/exceptions/DefaultDataFetcherExceptionHandler.kt b/graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/exceptions/DefaultDataFetcherExceptionHandler.kt index c61658736..308ac0821 100644 --- a/graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/exceptions/DefaultDataFetcherExceptionHandler.kt +++ b/graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/exceptions/DefaultDataFetcherExceptionHandler.kt @@ -64,7 +64,7 @@ class DefaultDataFetcherExceptionHandler : DataFetcherExceptionHandler { } private fun unwrapCompletionException(e: Throwable): Throwable { - return if(e is CompletionException && e.cause != null) e.cause!! else e + return if (e is CompletionException && e.cause != null) e.cause!! else e } companion object { diff --git a/graphql-dgs/src/test/kotlin/com/netflix/graphql/dgs/exceptions/DefaultDataFetcherExceptionHandlerTest.kt b/graphql-dgs/src/test/kotlin/com/netflix/graphql/dgs/exceptions/DefaultDataFetcherExceptionHandlerTest.kt index fa9e320a6..52a4fb67d 100644 --- a/graphql-dgs/src/test/kotlin/com/netflix/graphql/dgs/exceptions/DefaultDataFetcherExceptionHandlerTest.kt +++ b/graphql-dgs/src/test/kotlin/com/netflix/graphql/dgs/exceptions/DefaultDataFetcherExceptionHandlerTest.kt @@ -130,8 +130,10 @@ internal class DefaultDataFetcherExceptionHandlerTest { @Test fun `CompletionException returns wrapped error code`() { - val completionException = CompletionException("com.netflix.graphql.dgs.exceptions.DgsEntityNotFoundException: Requested entity not found", - DgsEntityNotFoundException()) + val completionException = CompletionException( + "com.netflix.graphql.dgs.exceptions.DgsEntityNotFoundException: Requested entity not found", + DgsEntityNotFoundException() + ) every { dataFetcherExceptionHandlerParameters.exception }.returns(completionException) val result = DefaultDataFetcherExceptionHandler().handleException(dataFetcherExceptionHandlerParameters).get()