【问题标题】:GraphQL response type / fragment struggleGraphQL 响应类型/片段之争
【发布时间】:2019-05-14 04:38:26
【问题描述】:

我在 graphql 中编写 API 时遇到了一些困难。

我的 api 中的每个响应看起来都差不多。 所以理想情况下,这将是 graphql 类型:

type Response {
  success
  data {
    ... always different
  }
  errors {
    path
    message
  }
}

但是因为这里的数据字段总是不同的。每个突变/查询都应该有自己的响应类型(如果我正确理解了 graphql)。

所以对于登录,这是我使用转换器函数创建的类型:

type LoginResponse {
  success
  data {
    user
    token
  }
  errors {
    path
    message
  }
}

现在在我的前端,我想使用以下片段,因为这些属性始终存在于每个响应中。

fragment Response on LoginResponse {
  success
  errors {
    path
    message
  }
}

所以这里已经显示了我遇到的问题,您还可以使用片段定义它的父类型。因此,我必须创建与单独响应类型一样多的单独片段。

是否有人可能已经为此苦苦挣扎,或者是否有我没有看到的最佳实践

【问题讨论】:

    标签: graphql apollo graphql-js graphql-tag


    【解决方案1】:

    一般来说,当您有一个可以解析为多种类型之一的字段时,您可以使用联合。如果这些类型共享一个或多个字段,您可能希望改用接口。

    您在模式中看到的一个常见模式是Node 接口的概念。您可以通过 id 获取节点的查询,例如:

    type Query {
      node(id: ID!): Node
    }
    
    interface Node {
      id: ID!
    }
    
    type Foo implements Node {
      id: ID!
      foo: String!
    }
    
    type Bar implements Node {
      id: ID!
      bar: Int!
    }
    

    这里,Node 可以是FooBar,所以如果我们要为Node 编写一个片段,它可能看起来像这样:

    fragment NodeFields on Node {
      id # id is part of the interface itself
      ... on Bar {
        bar # fields specific to Bar
      }
      ... on Foo {
        foo # fields specific to Foo
      }
    }
    

    如果您没有共享字段,则可以使用联合来代替:

    union SomeUnion = Foo | Bar
    

    因此,为了减少前端代码中的一些重复,您可以将每个 Result 类型设置为接口,或者更好的是,使用单个 Result 类型,data 是一个联合。不幸的是,接口或联合都不能与标量或列表一起使用,如果 data 应该是某些查询的标量或列表,这会使事情变得复杂。

    不过,归根结底,首先以这种方式构建架构可能并不可取。避免这种结构的原因有很多:

    1. GraphQL 已经将您的查询结果作为带有 dataerrors 属性的 JSON 对象返回。
    2. 在 GraphQL data 中返回错误将需要额外的逻辑来捕获和格式化错误,而不是仅仅在任何地方抛出错误并让 GraphQL 为您处理错误报告。
    3. 您将无法捕获验证错误,因此您可能会在两个地方出现错误——errors 数组内部和data.errors 内部。这也意味着您的客户需要在两个位置查找错误以进行正确的错误处理。
    4. GraphQL 专门设计用于允许部分解析响应。这意味着即使响应的某些部分出错并且无法解析,其他部分仍可能被解析并作为响应的一部分返回。这意味着响应“成功”的概念在 GraphQL 中并不真正适用。如果您绝对需要 success 字段,最好在查询解析后使用 formatResponse 之类的内容将其添加到响应对象中。

    这将使遵守约定的事情变得更加简单,并按照以下原则构建您的架构:

    type Query {
      login: LoginResponse
    }
    
    type LoginResponse {
      token: String
      user: User
    }
    

    实际的回复还是会包含dataerrors

    {
      "data": {
        "login": {
          "token": "",
        }
      },
      "errors": []
    }
    

    如果您甚至需要使用片段,您仍然需要每种类型一个片段,但片段之间的重复次数会大大减少。

    【讨论】:

    • 这正是我正在寻找的解释类型。非常感谢人!重构我的响应并尝试自动错误 rn。我以前见过工会,但不知道你也可以在上面分段。
    • ? 值得指出的是,除了formatResponse,您还可以使用formatError 函数配置ApolloServer,以便更好地控制您的错误在响应中的返回方式.
    【解决方案2】:

    关于如何处理错误的好视频(与此问题相关):https://www.youtube.com/watch?v=-wRXk_QZ3Ko

    【讨论】:

      猜你喜欢
      • 2020-08-10
      • 2022-12-17
      • 2020-10-20
      • 2018-11-30
      • 2020-01-19
      • 2021-06-20
      • 2020-04-22
      • 1970-01-01
      • 2018-12-18
      相关资源
      最近更新 更多