假设我的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数据转换为使用人员
的数组,但是没有办法处理这样的数据吗?
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