# Directive Design

Directives play an important role: they allow to implement those features which are not natively-supported by the GraphQL spec or by the GraphQL server itself. Directives can then help fill the void in terms of functionality, so that the API can satisfy its requirements, either known or unknown ones.

For this reason, directives are an extremely important element within the foundations of the GraphQL server. GraphQL by PoP relies on a sound and solid architectural design for directives, which enables it to become both extensible and powerful.

# Low-level functionality

As a design decision, the engine depends directly on the directive pipeline for resolving the query. For this reason, directives are treated as low-level components, with access to the object where the response is stored.

As a result, any custom directive has the power to modify the GraphQL response.

An evident use case for this is directive @removeIfNull (implemented here), which allows to indicate in the query if we'd rather omit the response from a field than to receive a null value (there is an issue in the spec concerning this feature).

# Efficient directive calls

Directives receive all their affected objects and fields together, for a single execution.

In the examples below, the Google Translate API is called the minimum possible amount of times to execute multiple translations.

In this query, the Google Translate API is called once, containing 10 pieces of text to translate (2 fields, title and excerpt, for 5 posts):

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

In this query there are 3 calls to the API, one for every language (Spanish, French and German), 10 strings each, all calls are concurrent:

query {
  posts(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")
  }
}
View PQL queries
// The Google Translate API is called once, containing 10 pieces of text to translate (2 fields, title and excerpt, for 5 posts)
/?query=
  posts(limit:5).
    --props|
    --props@spanish<
      translate(en,es)
    >&
props=
  title|
  excerpt

// Here there are 3 calls to the API, one for every language (Spanish, French and German), 10 strings each, all calls are concurrent
/?query=
  posts(limit:5).
    --props|
    --props@spanish<
      translate(en,es)
    >|
    --props@french<
      translate(en,fr)
    >|
    --props@german<
      translate(en,de)
    >&
props=
  title|
  excerpt

[View results: query #1, query #2]

# Function signature

This is the directive interface. Please notice the parameters that function resolveDirective receives:

public function resolveDirective(
  TypeResolverInterface $typeResolver,
  array &$idsDataFields,
  array &$succeedingPipelineIDsDataFields,
  array &$succeedingPipelineDirectiveResolverInstances,
  array &$resultIDItems,
  array &$unionDBKeyIDs,
  array &$dbItems,
  array &$previousDBItems,
  array &$variables,
  array &$messages,
  array &$dbErrors,
  array &$dbWarnings,
  array &$dbDeprecations,
  array &$dbNotices,
  array &$dbTraces,
  array &$schemaErrors,
  array &$schemaWarnings,
  array &$schemaDeprecations,
  array &$schemaNotices,
  array &$schemaTraces
): void;

These parameters evidence the low-level nature of the directive:

  • $idsDataFields: the list of IDs per field to be processed by the directive
  • $succeedingPipelineIDsDataFields: the list of IDs per field to be processed by directives at a later stage in the pipeline
  • $resultIDItems: the response object

The other parameters make it possible to: access the query variables and define dynamic variables (as done by the @export directive), pass messages with custom data across directives, raise errors and warnings, identify and display deprecations, pass notices to the user, and store metrics.

Last Updated: 7/24/2020, 3:22:39 PM