Conception des directives
Les directives jouent un rôle important : elles permettent d'implémenter les fonctionnalités qui ne sont pas nativement supportées par la spécification GraphQL ou par le serveur GraphQL lui-même. Les directives peuvent ainsi combler ce vide fonctionnel, afin que l'API puisse satisfaire ses exigences, qu'elles soient connues ou inconnues.
Pour cette raison, les directives sont un élément extrêmement important au sein des fondations du serveur GraphQL. Gato GraphQL s'appuie sur une conception architecturale solide et robuste pour les directives, ce qui lui permet d'être à la fois extensible et puissant.
Fonctionnalité de bas niveau
En tant que décision de conception, le moteur dépend directement du pipeline de directives pour résoudre la requête. Pour cette raison, les directives sont traitées comme des composants de bas niveau, avec accès à l'objet où la réponse est stockée.
En conséquence, toute directive personnalisée a la capacité de modifier la réponse GraphQL.
Un cas d'utilisation évident est la directive @remove, qui permet d'indiquer dans la requête si l'on préfère omettre la réponse d'un champ plutôt que de recevoir une valeur null (il existe une issue dans la spécification concernant cette fonctionnalité).
Appels efficaces aux directives
Les directives reçoivent tous leurs objets et champs affectés ensemble, en une seule exécution.
Par exemple, appeler l'API Google Translate doit être fait le moins souvent possible. Dans cette requête, elle n'est appelée qu'une seule fois, contenant 10 morceaux de texte à traduire (2 champs, title et excerpt, pour 5 posts) :
query {
posts(pagination:{ limit: 5 }) {
title
excerpt
titleES: title @translate(from: "en", to: "es")
excerptES: excerpt @translate(from: "en", to: "es")
}
}Dans cette requête, il y a 3 appels à l'API, un par langue (espagnol, français et allemand), 10 chaînes chacun, tous les appels sont concurrents :
query {
posts(pagination:{ limit: 5 }) {
title
excerpt
titleES: title @translate(from: "en", to: "es")
excerptES: excerpt @translate(from: "en", to: "es")
titleDE: title @translate(from: "en", to: "de")
excerptDE: excerpt @translate(from: "en", to: "de")
titleFR: title @translate(from: "en", to: "fr")
excerptFR: excerpt @translate(from: "en", to: "fr")
}
}Signature de la fonction
Voici l'interface de directive de champ. Remarquez les paramètres que la fonction resolveDirective reçoit :
public function resolveDirective(
RelationalTypeResolverInterface $relationalTypeResolver,
array $idFieldSet,
FieldDataAccessProviderInterface $fieldDataAccessProvider,
array $succeedingPipelineFieldDirectiveResolvers,
array $idObjects,
array $unionTypeOutputKeyIDs,
array $previouslyResolvedIDFieldValues,
array &$succeedingPipelineIDFieldSet,
array &$succeedingPipelineFieldDataAccessProviders,
array &$resolvedIDFieldValues,
array &$messages,
EngineIterationFeedbackStore $engineIterationFeedbackStore,
): void;Ces paramètres mettent en évidence la nature de bas niveau de la directive :
$idFieldSet: la liste des identifiants par champ à traiter par la directive$succeedingPipelineIDFieldSet: la liste des identifiants par champ à traiter par les directives à des étapes ultérieures du pipeline$resolvedIDFieldValues: l'objet de réponse
Les autres paramètres permettent de : accéder aux variables de la requête et définir des variables dynamiques, transmettre des messages avec des données personnalisées entre directives, générer des erreurs et des avertissements, identifier et afficher les dépréciations, et stocker des métriques.