アーキテクチャ
アーキテクチャディレクティブの設計

ディレクティブの設計

ディレクティブは重要な役割を果たします。GraphQL仕様やGraphQLサーバー自体がネイティブにサポートしていない機能を実装するために活用できます。ディレクティブは機能面のギャップを埋め、APIが既知・未知を問わず要件を満たせるようにします。

このため、ディレクティブはGraphQLサーバーの基盤において非常に重要な要素です。Gato GraphQLはディレクティブに対して健全で堅固なアーキテクチャ設計を採用しており、拡張性と強力な機能を両立させています。

低レベルの機能

設計上の判断として、エンジンはクエリを解決するためにディレクティブパイプラインに直接依存しています。このため、ディレクティブは低レベルコンポーネントとして扱われ、レスポンスが格納されるオブジェクトへのアクセス権を持ちます。

その結果、カスタムディレクティブはGraphQLレスポンスを変更する力を持ちます。

この明確な使用例として、@removeディレクティブがあります。これはフィールドのレスポンスとしてnull値を受け取るよりも省略したい場合に、クエリ内で指定できるものです(この機能に関する仕様のissueが存在します)。

効率的なディレクティブの呼び出し

ディレクティブは、影響を受けるすべてのオブジェクトとフィールドをまとめて受け取り、一度の実行で処理します。

たとえば、Google Translate APIの呼び出し回数は最小限に抑える必要があります。次のクエリでは、5件の投稿に対して2つのフィールド(titleとexcerpt)を翻訳する計10件のテキストを含み、APIの呼び出しは1回だけです。

query {
  posts(pagination:{ limit: 5 }) {
    title
    excerpt
    titleES: title @translate(from: "en", to: "es")
    excerptES: excerpt @translate(from: "en", to: "es")
  }
}

次のクエリでは、言語(スペイン語・フランス語・ドイツ語)ごとに1回ずつ、計3回のAPI呼び出しが行われます。各呼び出しには10件の文字列が含まれ、すべて並行して実行されます。

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")
  }
}

関数シグネチャ

以下はフィールドディレクティブのインターフェースです。関数resolveDirectiveが受け取るパラメータに注目してください。

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;

これらのパラメータは、ディレクティブの低レベルな性質を示しています。

  • $idFieldSet: ディレクティブが処理するフィールドごとのIDのリスト
  • $succeedingPipelineIDFieldSet: パイプラインの後続ステージでディレクティブが処理するフィールドごとのIDのリスト
  • $resolvedIDFieldValues: レスポンスオブジェクト

その他のパラメータにより、クエリ変数へのアクセスや動的変数の定義、カスタムデータを含むメッセージのディレクティブ間での受け渡し、エラーや警告の発生、非推奨の特定と表示、メトリクスの保存が可能になります。