假设我的graphql服务器想要将以下数据作为JSON获取,其中person3
和person5
是某些ID:
"persons": {
"person3": {
"id": "person3",
"name": "Mike"
},
"person5": {
"id": "person5",
"name": "Lisa"
}
}
问题:如何使用apollo创建模式类型定义?
此处的密钥person3
和person5
是根据我的查询动态生成的(即查询中使用的area
)。所以在另一个时间我可能会返回person1
,person2
,person3
。
如您所见persons
不是Iterable,所以以下内容不能用作我用apollo做的graphql类型定义:
type Person {
id: String
name: String
}
type Query {
persons(area: String): [Person]
}
persons
对象中的键可能总是不同。
当然,一种解决方案是将传入的JSON数据转换为persons
使用数组,但是没有办法处理数据吗?
答案 0 :(得分:12)
GraphQL依赖于服务器和客户端,提前知道每种类型可用的字段。在某些情况下,客户端可以发现这些字段(通过内省),但对于服务器,它们总是需要提前知道。因此,以某种方式根据返回的数据动态生成这些字段是不可能的。
您可以使用自定义JSON scalar并将其返回给您的查询:
type Query {
persons(area: String): JSON
}
通过使用JSON,您可以绕过返回数据的要求以适应任何特定结构,因此只要格式正确的JSON,您就可以发回任何您想要的内容。
当然,这样做存在明显的缺点。例如,您丢失了之前使用的类型所提供的安全网(实际上可以返回任何结构,如果您返回错误的结构,在客户端尝试之前您将无法找到它)使用它并失败)。您还失去了对返回数据中的任何字段使用解析器的功能。
但是......你的葬礼:)。
顺便说一句,在将数据发送回客户端之前,我会考虑将数据扁平化为数组(就像您在问题中建议的那样)。如果您正在编写客户端代码,并使用动态大小的客户列表,则可能更容易使用数组而不是id键入的对象。例如,如果您正在使用React并为每个客户显示一个组件,那么您最终会将该对象转换为数组以进行映射。在设计API时,我会更加重视客户可用性,而不是避免额外处理数据。
答案 1 :(得分:0)
您可以编写自己的GraphQLScalarType
并精确描述对象和动态键,允许的内容以及不允许或转换的内容。
请参见https://graphql.org/graphql-js/type/#graphqlscalartype
您可以看看taion/graphql-type-json,他在其中创建了一个标量,该标量允许并转换任何类型的内容:
https://github.com/taion/graphql-type-json/blob/master/src/index.js
答案 2 :(得分:0)
我在模式中的动态键上也遇到了类似的问题,最终得到了这样的解决方案:
list1=[1,2,3,4,5]
list2=list1[3:]
print(id(list1[3])==id(list2[0]))
list2[0]=7
print(list1,list2)
返回:
query lookupPersons {
persons {
personKeys
person3: personValue(key: "person1") {
id
name
}
}
}
通过将复杂度转移到查询,可以简化响应形状。 与JSON方法相比,优点是不需要客户端进行反序列化