如何使用graphQL返回错误数组

时间:2017-05-23 09:30:04

标签: node.js graphql hapijs

如何返回这样的多条错误消息?

"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数组添加多个错误?

5 个答案:

答案 0 :(得分:1)

使用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中使用VError,它可以让您在一个错误实例中表示许多错误。

答案 1 :(得分:0)

您需要在没有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 :(得分:0)

看起来问题不是要显示许多异常,而是要显示错误的所有堆栈跟踪。当抛出一个错误时,执行将不会收到或抛出其他错误。在某些语言中,您可以将父异常本机地设置为当前异常,但不是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 :(得分:0)

您可以使用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 :(得分:0)

抛出一个错误对象,其中包含errors:[]。 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"
    }
  ]
}