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

时间:2017-10-04 10:24:38

标签: graphql apollo apollo-server

假设我的graphql服务器想要将以下数据作为JSON获取,其中person3person5是某些ID:

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

问题:如何使用apollo创建模式类型定义?

此处的密钥person3person5是根据我的查询动态生成的(即查询中使用的area)。所以在另一个时间我可能会返回person1person2person3。 如您所见persons不是Iterable,所以以下内容不能用作我用apollo做的graphql类型定义:

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

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

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

3 个答案:

答案 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方法相比,优点是不需要客户端进行反序列化