具有动态键的对象的Apollo/GraphQL字段类型[英] Apollo/GraphQL field type for object with dynamic keys

本文是小编为大家收集整理的关于具有动态键的对象的Apollo/GraphQL字段类型的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

假设我的GraphQl Server想要获取以下数据为JSON,其中person3和person5是某些ID:

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

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

键person3和person5此处是根据我的查询(即查询中使用的area)动态生成的.因此,在另一个时间,我可能会得到person1,person2,person3返回. 如您所见,persons不是一个可觉得的,因此以下内容无法用Apollo进行的GraphQl类型定义来工作:

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

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

当然,一种解决方案是将传入的JSON数据转换为使用persons的数组,但是是否可以这样处理数据?

推荐答案

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

you 可以使用自定义 json stalcor -type-json模块)并返回您的查询:

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

通过使用JSON,您绕过了对返回数据的要求,以适合任何特定的结构,因此您可以将任何想要的内容发送回JSON.

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

但是...您的葬礼:)

顺便说一句,在将数据发送回客户端之前,我将考虑将数据弄平到阵列(如您在问题中所建议).如果您正在编写客户端代码,并且使用动态大小的客户列表,那么很可能会更容易使用数组,而不是由ID键键入的对象.例如,如果您使用React,并为每个客户显示一个组件,则最终将该对象转换为数组以映射它.在设计您的API时,我将使客户的可用性比避免进行其他数据处理更高.

其他推荐答案

您可以编写自己的GraphQLScalarType,并精确地描述您的对象和动态键,允许的内容以及不允许或不允许的东西.

参见/a>

您可以看看 taion/graphql-type-json 创建允许和转换任何类型内容的标量:

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
}

顺便说一句,如果您的数据集变得足够大,您可能还要在personKeys上进行分页,此时,您应该研究 https://relay.dev/graphql/connections.htm

本文地址:https://www.itbaoku.cn/post/1938022.html

问题描述

Let's say my graphql server wants to fetch the following data as JSON where person3 and person5 are some id's:

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

Question: How to create the schema type definition with apollo?

The keys person3 and person5 here are dynamically generated depending on my query (i.e. the area used in the query). So at another time I might get person1, person2, person3 returned. As you see persons is not an Iterable, so the following won't work as a graphql type definition I did with apollo:

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

The keys in the persons object may always be different.

One solution of course would be to transform the incoming JSON data to use an array for persons, but is there no way to work with the data as such?

推荐答案

GraphQL relies on both the server and the client knowing ahead of time what fields are available available for each type. In some cases, the client can discover those fields (via introspection), but for the server, they always need to be known ahead of time. So to somehow dynamically generate those fields based on the returned data is not really possible.

You could utilize a custom JSON scalar (graphql-type-json module) and return that for your query:

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

By utilizing JSON, you bypass the requirement for the returned data to fit any specific structure, so you can send back whatever you want as long it's properly formatted JSON.

Of course, there's significant disadvantages in doing this. For example, you lose the safety net provided by the type(s) you would have previously used (literally any structure could be returned, and if you're returning the wrong one, you won't find out about it until the client tries to use it and fails). You also lose the ability to use resolvers for any fields within the returned data.

But... your funeral :)

As an aside, I would consider flattening out the data into an array (like you suggested in your question) before sending it back to the client. If you're writing the client code, and working with a dynamically-sized list of customers, chances are an array will be much easier to work with rather than an object keyed by id. If you're using React, for example, and displaying a component for each customer, you'll end up converting that object to an array to map it anyway. In designing your API, I would make client usability a higher consideration than avoiding additional processing of your data.

其他推荐答案

You can write your own GraphQLScalarType and precisely describe your object and your dynamic keys, what you allow and what you do not allow or transform.

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

You can have a look at taion/graphql-type-json where he creates a Scalar that allows and transforms any kind of content:

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

其他推荐答案

I had a similar problem with dynamic keys in a schema, and ended up going with a solution like this:

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

returns:

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

by shifting the complexity to the query, it simplifies the response shape. the advantage compared to the JSON approach is it doesn't need any deserialisation from the client

Additional info for Venryx: a possible schema to fit my query looks like this:

type Person {
  id: String
  name: String
}

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

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

As an aside, if your data set for persons gets large enough, you're going to probably want pagination on personKeys as well, at which point, you should look into https://relay.dev/graphql/connections.htm