Supposons que mon serveur graphql veuille récupérer les données suivantes au format JSON où person3
et person5
sont des identifiants:
"persons": {
"person3": {
"id": "person3",
"name": "Mike"
},
"person5": {
"id": "person5",
"name": "Lisa"
}
}
Question: Comment créer la définition de type de schéma avec apollo?
Les clés person3
et person5
ici sont générés dynamiquement en fonction de ma requête (c'est-à-dire le area
utilisé dans la requête). Donc à un autre moment, je pourrais avoir person1
, person2
, person3
revenu. Comme vous le voyez, persons
n'est pas un Iterable, donc ce qui suit ne fonctionnera pas comme une définition de type graphql que j'ai faite avec apollo:
type Person {
id: String
name: String
}
type Query {
persons(area: String): [Person]
}
Les clés de l'objet persons
peuvent toujours être différentes.
Une solution serait bien sûr de transformer les données JSON entrantes pour utiliser un tableau pour persons
, mais n'y a-t-il aucun moyen de travailler avec les données en tant que telles?
GraphQL repose à la fois sur le serveur et sur le client sachant à l'avance quels champs sont disponibles disponibles pour chaque type. Dans certains cas, le client peut découvrir ces champs (via l'introspection), mais pour le serveur, ils doivent toujours être connus à l'avance. Il n'est donc pas vraiment possible de générer dynamiquement ces champs en fonction des données renvoyées.
Vous pourriez utiliser un scalaire JSON personnalisé (module graphql-type-json) et le renvoyer pour votre requête:
type Query {
persons(area: String): JSON
}
En utilisant JSON, vous contournez l'exigence que les données retournées correspondent à n'importe quelle structure spécifique, de sorte que vous pouvez renvoyer ce que vous voulez tant qu'il est correctement formaté JSON.
Bien sûr, cela présente des inconvénients importants. Par exemple, vous perdez le filet de sécurité fourni par le (s) type (s) que vous auriez précédemment utilisé (littéralement n'importe quelle structure pourrait être retournée, et si vous retournez la mauvaise, vous ne le découvrirez pas tant que le client n'aura pas essayé pour l'utiliser et échoue). Vous perdez également la possibilité d'utiliser des résolveurs pour tous les champs des données renvoyées.
Mais ... vos funérailles :)
En passant, j'envisagerais d'aplatir les données dans un tableau (comme vous l'avez suggéré dans votre question) avant de les renvoyer au client. Si vous écrivez le code client et travaillez avec une liste de clients de taille dynamique, il est probable qu'un tableau sera beaucoup plus facile à utiliser qu'avec un objet indexé par id. Si vous utilisez React, par exemple, et affichez un composant pour chaque client, vous finirez par convertir cet objet en un tableau pour le mapper de toute façon. Lors de la conception de votre API, je ferais de l'utilisabilité du client une considération plus importante que d'éviter un traitement supplémentaire de vos données.
Vous pouvez écrire votre propre GraphQLScalarType
et décrire précisément votre objet et vos clés dynamiques, ce que vous autorisez et ce que vous n'autorisez pas ou ne transformez pas.
Voir https://graphql.org/graphql-js/type/#graphqlscalartype
Vous pouvez voir taion/graphql-type-json où il crée un scalaire qui autorise et transforme tout type de contenu:
https://github.com/taion/graphql-type-json/blob/master/src/index.js
J'ai eu un problème similaire avec les clés dynamiques dans un schéma et j'ai fini par choisir une solution comme celle-ci:
query lookupPersons {
persons {
personKeys
person3: personValue(key: "person1") {
id
name
}
}
}
retour:
{
data: {
persons: {
personKeys: ["person1", "person2", "person3"]
person3: {
id: "person3"
name: "Mike"
}
}
}
}
en déplaçant la complexité vers la requête, il simplifie la forme de la réponse. l'avantage par rapport à l'approche JSON est qu'il n'a pas besoin de désérialisation du client