error-handling - 在 graphql 中执行多个突变时的正确错误处理

标签 error-handling graphql mutation

鉴于以下 GraphQL 突变:

type Mutation {
  updateUser(id: ID!, newEmail: String!): User
  updatePost(id: ID!, newTitle: String!): Post
}

Apollo 文档指出,完全有可能在一个请求中执行多个更改,例如
mutation($userId: ID!, $newEmail: String!, $postId: ID!, $newTitle: String!) {
  updateUser(id: $userId, newEmail: $newEmail) {
    id
    email
  }
  updatePost(id: $postId, newTitle: $newTitle) {
    id
    title
  }
}

1. 真的有人这样做吗? 如果你不明确这样做,批处理会导致这种变异合并吗?

2.如果你在mutation中执行run multiple things,你会如何正确处理错误?

我见过很多人建议在服务器上抛出错误,以便服务器响应如下所示:
{
  errors: [
    {
      statusCode: 422,
      error: 'Unprocessable Entity'
      path: [
        'updateUser'
      ],
      message: {
        message: 'Validation failed',
        fields: {
          newEmail: 'The new email is not a valid email address.'
        }
      },
    },
    {
      statusCode: 422,
      error: 'Unprocessable Entity'
      path: [
        'updatePost'
      ],
      message: {
        message: 'Validation failed',
        fields: {
          newTitle: 'The given title is too short.'
        }
      },
    }
  ],
  data: {
    updateUser: null,
    updatePost: null,
  }
}

但是我怎么知道哪个错误属于哪个突变呢?我们不能假设 errors 中的第一个错误数组属于第一个突变,因为如果 updateUser成功,数组将简单地包含一个条目。然后我是否必须遍历所有错误并检查路径是否与我的突变名称匹配? :D

另一种方法是将错误包含在专用响应类型中,例如 UpdateUserResponseUpdatePostResponse .这种方法使我能够正确解决错误。
type UpdateUserResponse {
  error: Error
  user: User
}

type UpdatePostResponse {
  error: Error
  post: Post
}

但是我有一种感觉,这会使我的架构膨胀很多。

最佳答案

简而言之,是的,如果您包含多个顶级突变字段,请使用 path错误的属性以确定哪个突变失败。请注意,如果错误发生在图形的更深处(在某些子字段而不是根级字段上),路径将反射(reflect)该字段。即解析title时出现的执行错误字段将导致 pathupdatePost.title .

返回错误作为 data 的一部分是一个同样有效的选项。这种方法还有其他好处:

  • 像这样发送的错误可以包括额外的元数据(“代码”属性、有关可能产生错误的特定输入字段的信息等)。虽然可以通过 errors 发送相同的信息数组,使其成为架构的一部分意味着客户端将知道这些错误对象的结构。这对于用类型语言编写的客户端尤其重要,因为客户端代码通常是从模式生成的。
  • 以这种方式返回客户端错误可以让您清楚地区分应该让用户看到的用户错误(错误的凭据、用户已经存在等)与客户端或服务器代码实际出现的问题(在这种情况下,充其量,我们展示了一些通用消息)。
  • 创建像这样的“有效负载”对象可以让您在 future 附加其他字段而不会破坏您的架构。

  • 第三种选择是以类似的方式使用联合:
    type Mutation {
      updateUser(id: ID!, newEmail: String!): UpdateUserPayload!
    }
    
    union UpdateUserPayload = User | Error
    

    这使客户端能够使用片段和 __typename区分成功和失败突变的字段:
    mutation($userId: ID!, $newEmail: String!) {
      updateUser(id: $userId, newEmail: $newEmail) {
        __typename
        ... on User {
          id
          email
        }
        ... on Error {
          message
          code
        }
      }
    }
    

    您甚至可以为每种错误创建特定类型,允许您省略任何类型的“代码”字段:
    union UpdateUserPayload = User | EmailExistsError | EmailInvalidError
    

    这里没有正确或错误的答案。虽然每种方法都有其优点,但您采用哪种方法最终归结为偏好。

    关于error-handling - 在 graphql 中执行多个突变时的正确错误处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59596736/

    相关文章:

    Spring MVC 请求体错误处理

    python - 除了 OSError 为 (errcode , message) : SyntaxError: invalid syntax

    reactjs - Netlify CMS 无法更新/替换已在 Gatsby.js 中优化的图像

    vuex - 为什么更新数组中的对象在 VUE 中不起作用?

    python-3.x - 是否可以采用这种使用字典来查找/评估许多函数之一及其相应参数的方法?

    javascript - 如何在 JavaScript 中挽救对象的未定义属性?

    javascript - 使用 gatsby-source-google-spreadsheet 将表格中的链接插入 Gatsby

    javascript - 您能否过滤出只有一半的查询条目拥有的属性?

    genetic-algorithm - 在稳态遗传算法中应用变异

    javascript - 观察 DOM 属性