【问题标题】:How to return an array of errors with graphQL如何使用 graphQL 返回错误数组
【发布时间】:2017-10-23 04:15:51
【问题描述】:

我怎样才能返回多个这样的错误消息?

"errors": [
  {
    "message": "first error",
    "locations": [
      {
        "line": 2,
        "column": 3
      }
    ],
    "path": [
      "somePath"
    ]
  },
  {
    "message": "second error",
    "locations": [
      {
        "line": 8,
        "column": 9
      }
    ],
    "path": [
      "somePath"
    ]
  },
]

在我的服务器上,如果我执行throw('an error'),它会返回。

"errors": [
  {
    "message": "an error",
    "locations": [
      {
      }
    ],
    "path": ["somePath"]
  }
]

我想返回查询中所有错误的数组。 如何向errors 数组添加多个错误?

【问题讨论】:

  • 你在这方面找到什么了吗?
  • 没有一段时间没有在graphQL上工作过。

标签: node.js graphql hapijs


【解决方案1】:

您需要在没有throw 语句的情况下捕获错误,因为您不想中断您的进程。相反,您可以创建一个名为 errors 的数组,并将 .push() 错误放入其中。当您认为合适时,在您的流程接近尾声时,您可以检查错误数组中是否有错误。如果有,您可以随意显示或处理它们

// example
var errors = [];

doSomething(function(err,res){

    if(err){
        errors.push(err);
    }
    console.log("we did a thing");
    doSomethingElse(function(err,res2){

         if(err){
              errors.push(err);
         };
         console.log("we did another thing");

         // check and throw errors
         if(errors.length > 0){
             throw errors;
         }



    });

});

【讨论】:

  • 它没有返回多个错误对象,而是将所有错误消息添加到单个错误对象中。
【解决方案2】:

看起来问题不是要显示许多异常,而是要显示错误的所有堆栈跟踪。当抛出一个错误时,执行将不会接收或抛出其他错误。在某些语言中,您可以将父异常设置为当前异常,但 javascript 的情况并非如此,到目前为止,我可以告诉并查看文档 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Errorhttps://nodejs.org/api/errors.html#errors_error_propagation_and_interception。您将需要创建自己的错误类,这并不难。

如果问题是显示跟踪

Javascript 中的堆栈跟踪是一个字符串!如果您只想将其放入一些日志中,这很好,但如果您想制作更有意义的阅读结构,例如 json,则不好。

如果你真的想要显示堆栈跟踪,可能你需要将 Error 对象的堆栈跟踪转换为数组,使用如下所示: https://github.com/stacktracejs/error-stack-parser 然后将此数组放入错误对象中。

之后,您可以将该对象保存到您的数据库中。你仍然会只看到一个错误,但你会得到它的所有“位置”、“线”、“路径”,这听起来你在寻找什么。

如果问题是显示父错误消息和跟踪

如果您想保留某些跟踪的父错误,您可能需要创建自己的错误类。

   /**
    * Class MyError extends Error but add the parentError attribute
    */ 
   function MyError(message, parentError ) { 
      this.message = message; 
      this.stack = Error().stack; 
      this.parentError = parentError;
    }

    MyError.prototype = Object.create(Error.prototype); 
    MyError.prototype.name = "MyError";

    function a() {
      b();
    }

    function b() {
      try {
        c();
      } catch ( e ) {
        throw new MyError( "error on b", e );
      }
    }

    function c() {
      d();
    }

    function d() {
      throw new MyError("error on d");
    }

    function showError( e ) {
      var message = e.message + " " + e.stack;
      if ( e.parentError ) {
        return message + "\n" + showError( e.parentError );
      }
      return message;
    }

    try{
      a();  
    } catch ( e ) {
      console.log(showError( e ));
    }

如果问题是显示许多错误消息和跟踪

如果您想将许多错误保存在一个大包中,例如,为了验证反馈,您可以扩展错误类以创建一个错误包。我为每个此类创建了一个简单的示例。

   /**
    * Class MyErrorPackage extends Error 
    * but works like a error package
    */ 
    function MyErrorPackage(message, parentError ) { 
      this.packageErrors = [];
      this.message = "This package has errors. \n"; 
      this.isValid = true;
      this.stack = Error().stack; 
      this.parentError = parentError;
      this.addError = function addError( error ) {
         this.packageErrors.push( error );
         this.isValid = false;
         this.message += "PackageError(" + this.packageErrors.length + "): " + error.stack + error.stack + "\n";
         
      };
      this.validate = function validate() {
         if( ! this.isValid ) {
           throw this;
         }
      };
    }

    MyErrorPackage.prototype = Object.create(Error.prototype); 
    MyErrorPackage.prototype.name = "MyErrorPackage";
    
    function showError( e ) {
      var message = e.message + " " + e.stack;
      if ( e.parentError ) {
        return message + "\n" + showError( e.parentError );
      }
      return message;
    }

    function showPackageError( e ) {
      var message = e.message + " " + e.stack;
      if ( e.parentError ) {
        return message + "\n" + showError( e.parentError );
      }
      return message;
    }


    try{
      var p = new MyErrorPackage();
      try {
         throw new Error("error 1");
      } catch( e1 ) {
          p.addError(e1);
      }
      try {
         throw new Error("error 2");
      } catch( e2 ) {
          p.addError(e2);
      }
      try {
         throw new Error("error 3");
      } catch( e3 ) {
          p.addError(e3);
      }
      p.validate();
    } catch ( e4 ) {
      console.log(showError( e4 ));
    }

【讨论】:

    【解决方案3】:

    您可以使用 GraphQL 错误函数,我有一个 TypeScript 示例:

    function throwError(message: string, path: any) {
        throw new GraphQLError(
            message,
            [],
            {body: '', name: ''},
            undefined,
            [path]
        )
    }
    

    然后我只是根据需要多次调用该函数。

    JavaScript 构造函数如下所示:

    constructor(
        message: string,
        nodes?: $ReadOnlyArray<ASTNode> | ASTNode | void,
        source?: ?Source,
        positions?: ?$ReadOnlyArray<number>,
        path?: ?$ReadOnlyArray<string | number>,
        originalError?: ?Error,
        extensions?: ?{ [key: string]: mixed },
    ): void;
    

    查看graphql-js gitHub:

    https://github.com/graphql/graphql-js/blob/master/src/error/GraphQLError.js#L22

    【讨论】:

      【解决方案4】:

      抛出一个带有errors:[] 的错误对象。错误数组应该包含您想要汇总的所有错误。使用formatError 函数格式化错误输出。在下面的示例中,我使用的是 Apollo UserInputError。您也可以使用GraphQLError。没关系。

      const error = new UserInputError()
      error.errors = errorslist.map((i) => {
        const _error = new UserInputError()
        _error.path = i.path
        _error.message = i.type
        return _error
      })
      throw error
      
      new ApolloServer({
        typeDefs,
        resolvers,
        formatError: ({ message, path }) => ({
          message,
          path,
        }),
      })
      
      //sample output response
      {
        "data": {
          "createUser": null
        },
        "errors": [
          {
            "message": "format",
            "path": "username"
          },
          {
            "message": "min",
            "path": "phone"
          }
        ]
      }
      

      【讨论】:

        【解决方案5】:

        使用 ApolloServer 我发现在查询项目数组和 可选 字段的解析器错误时会返回多个错误。

        // Schema
        gql`
          type Foo {
            id: ID!
            bar: String # Optional
          }
        
          type Query {
            foos: [Foo!]!
          }
        `;
        
        // Resolvers
        const resolvers = {
          Query: {
            foos: () => [{ id: 1 }, { id: 2 }]
          }
          Foo: {
            bar: (foo) => {
               throw new Error(`Failed to get Foo.bar: ${foo.id}`);
            }
          }
        }
        
        // Query
        gql`
          query Foos {
            foos {
              id
              bar
            }
          }
        `;
        
        // Response
        {
          "data": {
            "foos": [{ id: 1, bar: null }, { id: 2, bar: null }]
          },
          "errors": [{
            "message": "Failed to get Foo.bar: 1"
          }, {
            "message": "Failed to get Foo.bar: 2"
          }]
        }
        

        如果Foo.bar 不是可选的,它将只返回第一个错误。

        如果您想一次返回许多错误,我会推荐 MultiError from VError,它允许您在一个错误实例中表示许多错误。

        【讨论】:

          猜你喜欢
          • 2018-09-24
          • 2019-02-02
          • 2017-04-15
          • 1970-01-01
          • 2023-03-06
          • 2020-09-26
          • 1970-01-01
          • 1970-01-01
          • 2019-05-14
          相关资源
          最近更新 更多