20

我在使用 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));

有谁能够帮我?

4

5 回答 5

35

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

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 }),
}));
于 2017-03-22T04:03:00.077 回答
11

最近在规范中添加了有关错误输出的内容:

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与此功能规范兼容,请查看错误处理

于 2018-07-03T12:05:55.927 回答
1

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

于 2019-09-08T17:20:23.550 回答
0

在对此进行了一段时间的试验后,我意识到缺少一些重要的细节。主要是,如果您有一个带有自定义字段的自定义错误对象,上述示例将允许您读取您的自定义属性,因为似乎自定义错误被转换为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
      }),
    }
  }));

originalError道具似乎总是被设置,但作为保障,您可以使用 lodash属性get

我有一个定义的自定义错误类,称为APIError

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

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

export default APIError;

在我的解析器中,我抛出如下异常:

  const e = new APIError({
    code: 500,
    message: 'Internal server error'
  });
于 2020-07-03T15:57:08.353 回答
0

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

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

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

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

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

于 2021-01-30T20:48:17.203 回答