提问者:小点点

具有动态键的对象的Apollo/GraphQL字段类型


假设我的graph ql服务器想要获取以下数据作为JSON其中人3人5是一些id:

"persons": {
  "person3": {
    "id": "person3",
    "name": "Mike"
  },
  "person5": {
    "id": "person5",
    "name": "Lisa"
  }
}

问题:如何使用apollo创建架构类型定义?

这里的键人3人5是根据我的查询(即查询中使用的区域)动态生成的。所以在另一个时候,我可能会返回人1人2人3。正如您所看到的不是Iterable,所以以下内容不适用于我对apollo所做的graph ql类型定义:

type Person {
  id: String
  name: String
}
type Query {
  persons(area: String): [Person]
}

对象中的键可能总是不同的。

一种解决方案当然是将传入的JSON数据转换为使用人员的数组,但是没有办法处理这样的数据吗?


共3个答案

匿名用户

GraphQL依赖于服务器和客户端提前知道每种类型有哪些可用字段。在某些情况下,客户端可以发现这些字段(通过自省),但对于服务器来说,它们总是需要提前知道。因此,以某种方式根据返回的数据动态生成这些字段是不可能的。

您可以使用自定义JSON标量(graph ql-type-json模块)并将其返回给您的查询:

type Query {
  persons(area: String): JSON
}

通过使用JSON,您可以绕过返回数据以适应任何特定结构的要求,因此您可以发送任何您想要的内容,只要它JSON格式正确。

当然,这样做有很大的缺点。例如,您失去了以前使用的类型提供的安全网(实际上任何结构都可以返回,如果您返回了错误的结构,您将无法发现它,直到客户端尝试使用它并失败)。您还失去了对返回数据中的任何字段使用解析器的能力。

但是…你的葬礼:)

顺便说一句,在将数据发送回客户端之前,我会考虑将数据平整成一个数组(就像你在问题中建议的那样)。如果你正在编写客户端代码,并使用动态大小的客户列表,那么数组可能比id键控的对象更容易使用。例如,如果你正在使用React,并为每个客户显示一个组件,你最终会将该对象转换为一个数组来映射它。在设计你的API时,我会将客户端可用性作为一个更高的考虑因素,而不是避免额外处理你的数据。

匿名用户

您可以编写自己的GraphQLScalarType并精确描述您的对象和动态键,您允许什么以及不允许或转换什么。

看https://graphql.org/graphql-js/type/#graphqlscalartype

您可以查看taion/graph ql-type-json,他在其中创建了一个允许和转换任何类型内容的Scalar:

https://github.com/taion/graphql-type-json/blob/master/src/index.js

匿名用户

我在模式中遇到了类似的动态键问题,最终采用了这样的解决方案:

query lookupPersons {
  persons {
    personKeys
    person3: personValue(key: "person3") {
      id
      name
    }
  }
}

返回:

{
  data: {
    persons: {
      personKeys: ["person1", "person2", "person3"]
      person3: {
        id: "person3"
        name: "Mike"
      }
    }
  }
}

通过将复杂性转移到查询,它简化了响应形状。与JSON方法相比,优点是它不需要客户端的任何反序列化

Venryx的附加信息:适合我的查询的可能模式如下所示:

type Person {
  id: String
  name: String
}

type PersonsResult {
  personKeys: [String]
  personValue(key: String): Person
}

type Query {
  persons(area: String): PersonsResult
}

顺便说一句,如果你的人员数据集变得足够大,你可能也想在人员键上分页,此时,你应该看看https://relay.dev/graphql/connections.htm