GraphQL Java以json格式发送自定义错误

问题描述:

我正在一个graphql应用程序中工作,无论它是否出现在servlet或服务中,我都必须在json中发送自定义错误对象/消息。

I am working in an graphql application where I have to send custom error object / message in json irrespective of whether it occurs in servlet or service.

预期的错误响应

{errorCode:400 //错误在这里,
errorMessage:我的错误消息}

如果有人可以指导我达到上述要求,将会很有帮助。

It will be helpful if someone could guide me to achieve the above requirement.

GraphQL规范为错误条目。

根据规范,它应该是这样的(假设使用JSON格式):

According to the spec, it should like this (assuming JSON format is used):

  "errors": [
    {
      "message": "Name for character with ID 1002 could not be fetched.",
      "locations": [ { "line": 6, "column": 7 } ],
      "path": [ "hero", "heroFriends", 1, "name" ]
      "extensions": {/* You can place data in any format here */}
    }
  ]

因此您将找不到一个允许您对其进行扩展并在GraphQL执行结果中返回类似内容的GraphQL实现,例如:

So you won't find a GraphQL implementation that allows you to extend it and return some like this in the GraphQL execution result, for example:

  "errors": [
    {
      "errorMessage": "Name for character with ID 1002 could not be fetched.",
      "errorCode": 404
    }
  ]

但是,该规范允许您以扩展条目。因此,您可以在服务器端创建一个自定义Exception,最后得到一个类似JSON的响应:

However, the spec lets you add data in whatever format in the extension entry. So you could create a custom Exception on the server side and end up with a response that looks like this in JSON:

  "errors": [
    {
      "message": "Name for character with ID 1002 could not be fetched.",
      "locations": [ { "line": 6, "column": 7 } ],
      "path": [ "hero", "heroFriends", 1, "name" ]
      "extensions": {
          "errorMessage": "Name for character with ID 1002 could not be fetched.",
          "errorCode": 404
      }
    }
  ]

很容易在GraphQL Java上实现,如文档。您可以创建一个覆盖 getExtensions 方法的自定义异常,并在实现内部创建一个映射,然后将其用于构建扩展的内容

It's quite easy to implement this on GraphQL Java, as described in the docs. You can create a custom exception that overrides the getExtensions method and create a map inside the implementation that will then be used to build the content of extensions:

public class CustomException extends RuntimeException implements GraphQLError {
    private final int errorCode;

    public CustomException(int errorCode, String errorMessage) {
        super(errorMessage);

        this.errorCode = errorCode;
    }

    @Override
    public Map<String, Object> getExtensions() {
        Map<String, Object> customAttributes = new LinkedHashMap<>();

        customAttributes.put("errorCode", this.errorCode);
        customAttributes.put("errorMessage", this.getMessage());

        return customAttributes;
    }

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

    @Override
    public ErrorType getErrorType() {
        return null;
    }
}

然后可以在代码中传递异常并从您的数据提取程序内部获取消息:

then you can throw the exception passing in the code and message from inside your data fetchers:

throw new CustomException(400, "A custom error message");

现在,还有另一种解决方法。

Now, there is another way to tackle this.

假设您正在使用Web应用程序,则可以以所需的任何格式返回错误(以及相关数据)。虽然在我看来这有点尴尬。 GraphQL客户端(如Apollo)遵守该规范,那么为什么要返回任何其他格式的响应?但是无论如何,那里有很多不同的要求。

Assuming you are working on a Web application, you can return errors (and data, for that matter) in whatever format that you want. Although that is a bit awkward in my opinion. GraphQL clients, like Apollo, adhere to the spec, so why would you want to return a response on any other format? But anyway, there are lots of different requirements out there.

一旦您拥有 ExecutionResult 的所有权,您可以创建任意格式的地图或对象,将其序列化为JSON并通过HTTP返回。

Once you get a hold of an ExecutionResult, you can create a map or object in whatever format you want, serialise that as JSON and return this over HTTP.

Map<String, Object> result = new HashMap<>();

result.put("data", executionResult.getData());

List<Map<String, Object>> errors = executionResult.getErrors()
        .stream()
        .map(error -> {
            Map<String, Object> errorMap = new HashMap<>();

            errorMap.put("errorMessage", error.getMessage());
            errorMap.put("errorCode", 404); // get the code somehow from the error object

            return errorMap;
        })
        .collect(toList());

result.put("errors", errors);

// Serialize "result" and return that.

但是,再次出现不符合规范的响应在大多数情况下没有意义

But again, having a response that doesn't comply with the spec doesn't make sense in most of the cases.