GraphQL 响应类型/片段之争

Posted

技术标签:

【中文标题】GraphQL 响应类型/片段之争【英文标题】:GraphQL response type / fragment struggle 【发布时间】: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
  

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

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

【问题讨论】:

【参考方案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 应该是某些查询的标量或列表,这会使事情变得复杂。

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

    GraphQL 已经将您的查询结果作为带有 dataerrors 属性的 JSON 对象返回。 在 GraphQL data 中返回错误将需要额外的逻辑来捕获和格式化错误,而不是仅仅在任何地方抛出错误并让 GraphQL 为您处理错误报告。 您将无法捕获验证错误,因此您可能会在两个地方出现错误——errors 数组内部和data.errors 内部。这也意味着您的客户需要在两个位置查找错误以进行正确的错误处理。 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

【讨论】:

以上是关于GraphQL 响应类型/片段之争的主要内容,如果未能解决你的问题,请参考以下文章

在 GraphQL 中重用输入类型作为片段 [重复]

从 TypeScript 类型定义或 GraphQL 片段定义生成 JavaScript 空对象

重用 GraphQL 片段

你如何在 python 中处理 graphql 查询和片段?

能够使用相同的字段扩展所有 Apollo/GraphQL 突变。通缉“通用片段”

使用模式对 GraphQL 响应进行类型保留反序列化