diff --git a/graphql/boot-graphql-webflux/src/main/java/com/example/graphql/config/ExceptionConfig.java b/graphql/boot-graphql-webflux/src/main/java/com/example/graphql/config/ExceptionConfig.java new file mode 100644 index 000000000..d4211178d --- /dev/null +++ b/graphql/boot-graphql-webflux/src/main/java/com/example/graphql/config/ExceptionConfig.java @@ -0,0 +1,18 @@ +package com.example.graphql.config; + +import org.springframework.boot.autoconfigure.web.ErrorProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ExceptionConfig { + + @Bean + ErrorProperties errorProperties() { + final ErrorProperties errorProp = new ErrorProperties(); + errorProp.setIncludeMessage(ErrorProperties.IncludeAttribute.ALWAYS); + errorProp.setIncludeException(true); + errorProp.setIncludeBindingErrors(ErrorProperties.IncludeAttribute.ALWAYS); + return errorProp; + } +} diff --git a/graphql/boot-graphql-webflux/src/main/java/com/example/graphql/exception/CustomExceptionResolver.java b/graphql/boot-graphql-webflux/src/main/java/com/example/graphql/exception/CustomExceptionResolver.java new file mode 100644 index 000000000..073569a98 --- /dev/null +++ b/graphql/boot-graphql-webflux/src/main/java/com/example/graphql/exception/CustomExceptionResolver.java @@ -0,0 +1,24 @@ +package com.example.graphql.exception; + +import graphql.ErrorType; +import graphql.GraphQLError; +import graphql.GraphqlErrorBuilder; +import graphql.schema.DataFetchingEnvironment; +import jakarta.validation.ConstraintViolationException; +import org.springframework.graphql.execution.DataFetcherExceptionResolverAdapter; +import org.springframework.stereotype.Component; + +@Component +public class CustomExceptionResolver extends DataFetcherExceptionResolverAdapter { + + @Override + protected GraphQLError resolveToSingleError(Throwable ex, DataFetchingEnvironment env) { + ConstraintViolationException validationException = (ConstraintViolationException) ex; + return GraphqlErrorBuilder.newError() + .errorType(ErrorType.ValidationError) + .message(validationException.getMessage()) + .path(env.getExecutionStepInfo().getPath()) + .location(env.getField().getSourceLocation()) + .build(); + } +} diff --git a/graphql/boot-graphql-webflux/src/main/java/com/example/graphql/exception/GlobalErrorWebExceptionHandler.java b/graphql/boot-graphql-webflux/src/main/java/com/example/graphql/exception/GlobalErrorWebExceptionHandler.java new file mode 100644 index 000000000..b56a09972 --- /dev/null +++ b/graphql/boot-graphql-webflux/src/main/java/com/example/graphql/exception/GlobalErrorWebExceptionHandler.java @@ -0,0 +1,44 @@ +package com.example.graphql.exception; + +import java.util.Map; +import org.springframework.boot.autoconfigure.web.ErrorProperties; +import org.springframework.boot.autoconfigure.web.WebProperties; +import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler; +import org.springframework.boot.web.reactive.error.ErrorAttributes; +import org.springframework.context.ApplicationContext; +import org.springframework.core.annotation.Order; +import org.springframework.http.MediaType; +import org.springframework.http.codec.ServerCodecConfigurer; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.server.*; +import reactor.core.publisher.Mono; + +@Component +@Order(-2) +public class GlobalErrorWebExceptionHandler extends DefaultErrorWebExceptionHandler { + + public GlobalErrorWebExceptionHandler( + ErrorAttributes errorAttributes, + ApplicationContext applicationContext, + ErrorProperties errorProperties, + ServerCodecConfigurer serverCodecConfigurer) { + super(errorAttributes, new WebProperties.Resources(), errorProperties, applicationContext); + super.setMessageReaders(serverCodecConfigurer.getReaders()); + super.setMessageWriters(serverCodecConfigurer.getWriters()); + } + + @Override + protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) { + return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse); + } + + @Override + protected Mono<ServerResponse> renderErrorResponse(ServerRequest request) { + Map<String, Object> error = + this.getErrorAttributes(request, this.getErrorAttributeOptions(request, MediaType.ALL)); + return ServerResponse.status(this.getHttpStatus(error)) + .contentType(MediaType.APPLICATION_JSON) + .body(BodyInserters.fromValue(error)); + } +}