Design von Direktiven
Direktiven spielen eine wichtige Rolle: Sie ermöglichen die Implementierung von Funktionen, die weder von der GraphQL-Spezifikation noch vom GraphQL-Server selbst nativ unterstützt werden. Direktiven können so die funktionale Lücke schließen, damit die API ihre Anforderungen erfüllen kann – bekannte wie unbekannte.
Aus diesem Grund sind Direktiven ein äußerst wichtiges Element im Fundament des GraphQL-Servers. Gato GraphQL basiert auf einem soliden und robusten architektonischen Design für Direktiven, das es sowohl erweiterbar als auch leistungsstark macht.
Low-level-Funktionalität
Als Design-Entscheidung hängt die Engine direkt von der Direktiven-Pipeline zur Auflösung der query ab. Aus diesem Grund werden Direktiven als Low-level-Komponenten behandelt, mit Zugriff auf das Objekt, in dem die Antwort gespeichert wird.
Dadurch hat jede benutzerdefinierte Direktive die Möglichkeit, die GraphQL-Antwort zu verändern.
Ein offensichtlicher Anwendungsfall dafür ist die @remove-Direktive, mit der du in der query angeben kannst, ob du die Antwort eines Feldes lieber weglassen möchtest, anstatt einen null-Wert zu erhalten (es gibt ein Issue in der Spezifikation zu dieser Funktion).
Effiziente Direktiven-Aufrufe
Direktiven erhalten alle betroffenen Objekte und Felder gemeinsam, in einer einzigen Ausführung.
Zum Beispiel sollte der Aufruf der Google Translate API so selten wie möglich erfolgen. In dieser query wird sie nur einmal aufgerufen und enthält 10 Textstücke zum Übersetzen (2 Felder, title und excerpt, für 5 Posts):
query {
posts(pagination:{ limit: 5 }) {
title
excerpt
titleES: title @translate(from: "en", to: "es")
excerptES: excerpt @translate(from: "en", to: "es")
}
}In dieser query gibt es 3 Aufrufe an die API, einen für jede Sprache (Spanisch, Französisch und Deutsch), je 10 Strings – alle Aufrufe erfolgen gleichzeitig:
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")
}
}Funktionssignatur
Dies ist das Field-Directive-Interface. Beachte die Parameter, die die Funktion resolveDirective erhält:
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;Diese Parameter verdeutlichen die Low-level-Natur der Direktive:
$idFieldSet: die Liste der IDs pro Feld, die von der Direktive verarbeitet werden sollen$succeedingPipelineIDFieldSet: die Liste der IDs pro Feld, die von Direktiven in einer späteren Phase der Pipeline verarbeitet werden sollen$resolvedIDFieldValues: das Antwortobjekt
Die anderen Parameter ermöglichen es: auf die query-Variablen zuzugreifen und dynamische Variablen zu definieren, Nachrichten mit benutzerdefinierten Daten zwischen Direktiven weiterzugeben, Fehler und Warnungen auszulösen, Deprecations zu identifizieren und anzuzeigen sowie Metriken zu speichern.