首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何处理Spring中的GraphQL查询验证错误

如何处理Spring中的GraphQL查询验证错误
EN

Stack Overflow用户
提问于 2022-06-10 01:30:13
回答 1查看 891关注 0票数 0

我有一个使用spring-boot-starter-graphql的简单Spring项目。这个项目有一个控制器,它接受一个参数。

代码语言:javascript
运行
复制
@Controller
public class HelloNameController {

    @QueryMapping
    public String hello(@Argument String name) {
        return "Hello " + name;
    }
}

这一论点是必要的。

Graphql模式

代码语言:javascript
运行
复制
 type Query {
     hello (name : String!) : String
  }

当我在Postman中调用这个API而不传递这个参数时,应用程序返回一个错误。我想重写这个错误消息的消息,但是我找不到方法去做它。在正式的文档中,它说要实现DataFetcherExceptionResolverAdapter,而我已经将它实现为bean

代码语言:javascript
运行
复制
@Configuration
public class GraphQLConfig {

    @Bean
    public DataFetcherExceptionResolver exceptionResolver() {
        return DataFetcherExceptionResolverAdapter.from((ex, env) -> {
            if (ex instanceof CoercingParseValueException) {

                return GraphqlErrorBuilder.newError(env).message("CoercingParseValueException")
                        .errorType(ErrorType.ExecutionAborted).build();
            }
            if (ex instanceof CoercingSerializeException) {
                return GraphqlErrorBuilder.newError(env).message("CoercingSerializeException")
                        .errorType(ErrorType.ExecutionAborted).build();
            } else {
                return null;
            }
        });
    }
}

问题是,这个错误从来没有达到这一点。如何捕获这种类型的错误并重写消息?

EN

回答 1

Stack Overflow用户

发布于 2022-06-30 00:50:22

我在GitHub上也问过一个类似的问题。graphql项目(#2866)和spring项目(#415)的响应相似.在撰写本报告时进行总结是不可能的。然后我创造了一个“解决办法”:

首先,创建一个实现GraphQLError的自定义异常类。

代码语言:javascript
运行
复制
import graphql.GraphQLError;
import graphql.language.SourceLocation;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.graphql.execution.ErrorType;
import org.springframework.http.HttpStatus;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Getter
@NoArgsConstructor
public class BadRequestException extends RuntimeException implements GraphQLError {

    private HttpStatus status = HttpStatus.BAD_REQUEST;

    private String message = "Resource not found";

    // Below code used for GraphQL only
    private List<SourceLocation> locations;

    public BadRequestException(String message, List<SourceLocation> locations) {
        this.message = message;
        this.locations = locations;
    }

    @Override
    public Map<String, Object> getExtensions() {
        Map<String, Object> customAttributes = new LinkedHashMap<>();
        customAttributes.put("errorCode", this.status.value());
        return customAttributes;
    }

    @Override
    public List<SourceLocation> getLocations() {
        return locations;
    }

    @Override
    public ErrorType getErrorType() {
        return ErrorType.BAD_REQUEST;
    }

    @Override
    public Map<String, Object> toSpecification() {
        return GraphQLError.super.toSpecification();
    }

}

其次,创建一个实现WebGraphQlInterceptor的拦截器类,并将其注释为@Component,这样Spring就可以将其创建为bean。在这个类中实现逻辑,以捕获所需的错误并将其转换为前面创建的异常类。

代码语言:javascript
运行
复制
import graphql.ErrorClassification;
import graphql.ErrorType;
import graphql.GraphQLError;
import graphql.validation.ValidationErrorType;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.graphql.ResponseError;
import org.springframework.graphql.server.WebGraphQlInterceptor;
import org.springframework.graphql.server.WebGraphQlRequest;
import org.springframework.graphql.server.WebGraphQlResponse;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Component
public class ErrorInterceptor implements WebGraphQlInterceptor {

    @Override
    public Mono<WebGraphQlResponse> intercept(WebGraphQlRequest request, Chain chain) {
        return chain.next(request)
                .map(response -> {
                    log.info("[ErrorInterceptor] Intercepting response... ");

                    List<GraphQLError> graphQLErrors = response.getErrors().stream()
                            .filter(error -> ErrorType.ValidationError.equals(error.getErrorType()))
                            .map(this::resolveException)
                            .collect(Collectors.toList());

                    if (!graphQLErrors.isEmpty()) {
                        log.info("[ErrorInterceptor] Found invalid syntax error! Overriding the message.");
                        return response.transform(builder -> builder.errors(graphQLErrors));
                    }

                    return response;
                });
    }

    private GraphQLError resolveException(ResponseError responseError) {

        ErrorClassification errorType = responseError.getErrorType();

        if (ErrorType.ValidationError.equals(errorType)) {
            String message = responseError.getMessage();
            log.info("[ErrorInterceptor] Returning invalid field error ");

            if (ValidationErrorType.NullValueForNonNullArgument.equals(
                    extractValidationErrorFromErrorMessage(responseError.getMessage()))) {
                String errorMessage =
                        "Field " + StringUtils.substringBetween(message, "argument ", " @") + " cannot be null";
                return new BadRequestException(errorMessage, responseError.getLocations());
            }
        }

        log.info("[ErrorInterceptor] Returning unknown query validation error ");
        return new BadRequestException("Unknown error", responseError.getLocations());
    }

    private ValidationErrorType extractValidationErrorFromErrorMessage(String message) {
        return ValidationErrorType.valueOf(StringUtils.substringBetween(message, "type ", ":"));
    }

}

这种方法的唯一问题是,所有需要的信息(比如错误类型、导致错误的字段等)都嵌入在本机错误消息中。因此,要提取所需的参数,我们必须解析字符串消息。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72568206

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档