【问题标题】:How to return both error and data in a graphql resolver?如何在 graphql 解析器中返回错误和数据?
【发布时间】:2023-03-06 23:11:01
【问题描述】:

我正在考虑实现包含错误和数据的 graphql 响应的方法。

是否可以在不创建包含error 的类型的情况下这样做?

例如

Mutation addMembersToTeam(membersIds: [ID!]! teamId: ID!): [Member] 将成员添加到某个团队。假设使用以下membersIds 调用此突变:[1, 2, 3]

id 为 1 和 2 的成员已经在团队中,因此必须抛出无法添加这些成员的错误,但应该添加 id 为 3 的成员,因为他不在团队中。

我正在考虑使用formatResponse,但似乎我无法在那里得到错误。

在返回类型中不添加错误字段是否可以解决这个问题?

【问题讨论】:

  • 您为什么不自定义您的回复?您可以在将错误发送给客户端之前捕获错误,然后创建自定义响应,例如包含添加成员的数组

标签: node.js apollo graphql-js


【解决方案1】:

是否可以在不给返回类型添加错误字段的情况下解决这个问题?

很遗憾,没有。

解析器可以返回数据,也可以返回 null 并引发错误。它不能两者兼得。澄清一下,可能得到部分响应和一些错误。一个简单的例子:

const typeDefs = `
  type Query {
    foo: Foo
  }

  type Foo {
    a: String
    b: String
  }
`
const resolvers = {
  Query: {
    foo: () => {},
  }
  Foo: {
    a: () => 'A',
    b: () => new Error('Oops!'),
  }
}

在本例中,查询foo 上的两个字段将产生以下响应:

{
  "data": {
    "foo": {
      "a": "A",
      "b": null
    }
  },
  "errors": [
    {
      "message": "Oops",
      "locations": [
        {
          "line": 6,
          "column": 5
        }
      ],
      "path": [
        "foo",
        "b"
      ]
    }
  ]
}

通过这种方式,可以同时发回数据和错误。但是你不能在同一个领域这样做,就像你的问题一样。有几种方法可以解决这个问题。正如您所指出的,您可以将错误作为响应的一部分返回,这通常是这样做的。然后,您可以使用formatResponse,遍历结果数据,提取任何错误并将它们与任何其他 GraphQL 错误结合起来。不是最佳的,但它可能会为您提供您正在寻找的行为。

另一种选择是修改突变,使其采用单个 memberId。然后,您可以为要添加的每个 id 请求单独的突变:

add1: addMemberToTeam(memberId: $memberId1 teamId: $teamId): {
  id
}
add2: addMemberToTeam(memberId: $memberId2 teamId: $teamId): {
  id
}
add3: addMemberToTeam(memberId: $memberId3 teamId: $teamId): {
  id
}

这在处理客户端时可能会比较棘手,而且效率当然较低,但同样可能会为您带来预期的行为。

【讨论】:

  • 使用 Apollo,服务器是否需要设置一些选项才能返回部分错误?我有一个可能返回“未经授权”的字段解析器,但是当未经授权的客户端请求该类型时,整个查询就会爆炸,并且响应具有data: null(不仅仅是该字段)。其他字段不需要授权,但不返回。
  • @DanDascalescu 听起来您的字段不可为空。如果在字段的解析器中抛出执行错误,则该字段将解析为 null……但如果该字段不可为空,则其父级将解析为 null,因为不可为空的字段不能为空。如果父字段也是不可为空的,那么它的父字段将解析为空...等等,直到我们点击data。请参阅规范中的here
【解决方案2】:

如果您考虑结合 GraphQL 错误 - 在 Apollo 中有一种方法可以做到这一点。 您需要将errorPolicy 设置为all。这将帮助您将错误通知用户,同时拥有尽可能多的数据。

none:这是匹配 Apollo Client 1.0 的默认策略 工作。任何 GraphQL 错误都被视为网络错误,并且 从响应中忽略任何数据。

忽略:忽略允许您 读取与 GraphQL 错误一起返回的任何数据,但不读取 保存错误或将它们报告到您的 UI。

all:使用 all 策略 是通知用户潜在问题的最佳方式 从您的服务器显示尽可能多的数据。它保存了两个数据 并将错误放入 Apollo 缓存中,以便您的 UI 可以使用它们。

但根据最佳实践,您不应该以这种方式操纵它。 这是一个great article,关于在 GraphQL 中处理错误。

因此,最好的方法是在响应中添加"errors" 字段并在JS 代码中处理。

【讨论】:

    【解决方案3】:

    我们可以通过使用联合来实现这一点。我会推荐访问伟大的文章Handling GraphQL errors like a champ

    例子:

    Mutation part: We can return the union type for the response & capture the result according to types.
    
    type MemberType {
      id: ID!
      name: String!
    }
    
    enum ErrorType {
      BAD_REQUEST_ERROR
      FORBIDDEN_ERROR
      INTERNAL_SERVER_ERROR
      NOT_FOUND_ERROR
      UNAUTHORIZED_ERROR
    }
    
    type GraphqlError {
      type: ErrorType!
      code: String!
      message: String!
      helpLink: URL
    }
    
    
    union UserRegisterResult = MemberType | GraphqlError;
    addMembersToTeam(membersIds: [ID!]! teamId: ID!): UserRegisterResult!
    
    Response:
    
    addMembersToTeam(membersIds: [ID!]! teamId: ID!): {
    ...on MemberType{
      id,
      name,
    }
    ...on GraphqlError{
      id,
      message,
      statusCode,
    }
    }
    

    【讨论】:

      猜你喜欢
      • 2018-11-28
      • 2020-03-04
      • 1970-01-01
      • 2017-05-13
      • 2020-10-04
      • 2021-03-01
      • 2019-08-24
      • 1970-01-01
      • 2018-09-24
      相关资源
      最近更新 更多