GraphQL - 如何使用不同的状态代码进行响应?

时间:2017-03-21 20:26:20

标签: javascript graphql apollo react-apollo

我在使用Graphql和Apollo Client时遇到了麻烦。

当我使用REST时,我总是创建不同的响应,如401代码,但在这里我不知道如何做类似的行为。

当我得到响应时,我希望它转到catch函数。 我在前面有这个代码:

client.query({
  query: gql`
    query TodoApp {
      todos {
        id
        text
        completed
      }
    }
  `,
})
  .then(data => console.log(data))
  .catch(error => console.error(error));

有人能帮助我吗?

5 个答案:

答案 0 :(得分:17)

在GraphQL中返回错误的方法(至少在graphql-js中)是在resolve函数中抛出错误。由于HTTP状态代码特定于HTTP传输,而GraphQL不关心传输,因此您无法在那里设置状态代码。你可以做的是在你的解析函数中抛出一个特定的错误:

age: (person, args) => {
  try {
    return fetchAge(person.id);
  } catch (e) {
    throw new Error("Could not connect to age service");
  }
}

GraphQL错误会在响应中发送到客户端,如下所示:

{
  "data": {
    "name": "John",
    "age": null
  },
  "errors": [
    { "message": "Could not connect to age service" }
  ]
}

如果消息信息不足,您可以为GraphQL服务器创建一个包含状态代码的特殊错误类。要确保状态代码包含在您的响应中,您必须在创建中间件时指定formatError函数:

app.use('/graphql', bodyParser.json(), graphqlExpress({ 
    schema: myGraphQLSchema,
    formatError: (err) => ({ message: err.message, status: err.status }),
}));

答案 1 :(得分:2)

spec最近增加了一个有关错误输出的信息:

  

GraphQL服务可以通过键扩展名提供错误的附加条目。如果设置了该条目,则其值必须具有一个映射。此项保留给实现者,用于为错误添加附加信息,但他们认为合适,并且对其内容没有附加限制。

现在,使用extensions字段,您可以为errors项自定义机器可读信息:

{
  "errors": [
    {
      "message": "Name for character with ID 1002 could not be fetched.",
      "locations": [ { "line": 6, "column": 7 } ],
      "path": [ "hero", "heroFriends", 1, "name" ],
      "extensions": {
        "code": "CAN_NOT_FETCH_BY_ID",
        "timestamp": "Fri Feb 9 14:33:09 UTC 2018"
      }
    }
  ]
}

Apollo-Server的最新版本与此功能兼容,请检出Here

答案 2 :(得分:0)

仅是对Glenn的回答的补充,here是Graphql Spec的一部分,它定义了应如何处理错误。因此,要知道请求是否失败(或部分失败),可以检查响应根目录中的“错误”键。

答案 3 :(得分:0)

尝试了一下之后,我意识到缺少一些重要的细节。主要是,如果您有一个带有自定义字段的自定义错误对象,上述示例将使您能够读取自定义属性,因为看来自定义错误被强制转换为仅具有message属性的标准A对象。

这是我的Error函数的外观(请注意formatError属性):

originalError

app.use('/graphql', auth.verifyAccess, graphqlHTTP((req, res) => { return { schema: makeExecutableSchema({ typeDefs: typeDefs, resolvers: rootResolver }), graphiql: true, formatError: (err) => ({ message: err.originalError.message || err.message, code: err.originalError.code || 500 }), } })); 属性似乎总是​​被设置,但是作为一种保护措施,您可以使用lodash的originalError属性。

我有一个名为get

的自定义错误类
APIError

在我的解析器中,我抛出诸如此类的异常:

class APIError extends Error {
  constructor({ code, message }) {
    const fullMsg = `${code}: ${message}`;

    super(fullMsg);
    this.code = code;
    this.message = message;
  }
}

export default APIError;

答案 4 :(得分:0)

我认为关于 graphql 和错误的讨论中缺少的一个问题是从 http 到 gql 的转换中的错误,这通常是 401 应该发生的地方。

在转换请求时,您应该将 Authorization 标头(或您使用的任何身份验证方法)转换为用户,如果无法通过身份验证,则应返回 HTTP 401 错误 - 这不是图表的一部分或api 的规范,只是用户是否可以被验证的问题。您甚至不必检查查询。

另一方面,403 错误很可能会出现在 gql 层(并且可能不会使用 http 状态代码,但这是另一个讨论),因为它可能非常特定于域,您必须知道查询决定是否禁止。

HTTP 403 状态可用于告诉用户他根本无法访问 gql api。

我们在 express/nestjs 中解决了这个问题,方法是在到达 graphql 层之前使用中间件来丰富用户的请求(可能未定义),或者如果用户无法通过身份验证则失败。如果您不提供凭据(或类似信息),我认为不应返回 401。