GraphQL响应类型/片段斗争



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

我的api中的每个响应看起来都应该是一样的。因此,理想情况下,这将是graphql类型:

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

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

所以对于Login,这是我用transformer函数创建的类型:

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

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

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

所以我遇到的问题已经在这里显示了,通过一个片段,你也可以定义它的父类型。所以我必须创建与单独的响应类型一样多的单独的片段。

有人可能已经为此感到挣扎了吗?或者有没有最好的做法?我没有看到

通常,当您有一个字段可以解析为多种类型中的一种时,您可以使用并集。如果这些类型共享一个或多个字段,则可能需要使用接口。

您在模式中看到的一个常见模式是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来达到同样的效果:

union SomeUnion = Foo | Bar

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

然而,在一天结束的时候,你可能不建议一开始就以这种方式构建你的模式。有很多很好的理由可以避免这种结构:

  1. GraphQL已经将查询结果作为具有dataerrors属性的JSON对象返回
  2. 返回GraphQLdata内部的错误将需要额外的逻辑来捕获和格式化错误,而不是仅仅在任何地方抛出错误并让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": []
}

如果你甚至需要使用片段,你仍然需要每个类型一个片段,但片段之间的重复会明显减少。

最新更新