Diseño de las directivas
Las directivas desempeñan un papel importante: permiten implementar aquellas funcionalidades que no están soportadas de forma nativa por la especificación de GraphQL ni por el propio servidor GraphQL. Las directivas pueden, por tanto, cubrir ese vacío funcional, de modo que la API pueda satisfacer sus requisitos, conocidos o desconocidos.
Por esta razón, las directivas son un elemento extremadamente importante dentro de los cimientos del servidor GraphQL. Gato GraphQL se apoya en un diseño arquitectónico sólido y robusto para las directivas, lo que le permite ser a la vez extensible y potente.
Funcionalidad de bajo nivel
Como decisión de diseño, el motor depende directamente del pipeline de directivas para resolver la consulta. Por esta razón, las directivas se tratan como componentes de bajo nivel, con acceso al objeto donde se almacena la respuesta.
Como resultado, cualquier directiva personalizada tiene la capacidad de modificar la respuesta GraphQL.
Un caso de uso evidente de esto es la directiva @remove, que permite indicar en la consulta si preferimos omitir la respuesta de un campo en lugar de recibir un valor null (existe una issue en la especificación acerca de esta funcionalidad).
Llamadas eficientes a las directivas
Las directivas reciben todos sus objetos y campos afectados juntos, en una única ejecución.
Por ejemplo, llamar a la API de Google Translate debería hacerse el menor número de veces posible. En esta consulta se llama una sola vez, conteniendo 10 fragmentos de texto a traducir (2 campos, title y excerpt, para 5 posts):
query {
posts(pagination:{ limit: 5 }) {
title
excerpt
titleES: title @translate(from: "en", to: "es")
excerptES: excerpt @translate(from: "en", to: "es")
}
}En esta consulta hay 3 llamadas a la API, una por cada idioma (español, francés y alemán), con 10 cadenas cada una, y todas las llamadas son concurrentes:
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")
}
}Firma de la función
Esta es la interfaz de la directiva de campo. Fíjate en los parámetros que recibe la función 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;Estos parámetros evidencian la naturaleza de bajo nivel de la directiva:
$idFieldSet: la lista de IDs por campo que debe procesar la directiva$succeedingPipelineIDFieldSet: la lista de IDs por campo que deben procesar las directivas en etapas posteriores del pipeline$resolvedIDFieldValues: el objeto de respuesta
Los demás parámetros permiten: acceder a las variables de la consulta y definir variables dinámicas, pasar mensajes con datos personalizados entre directivas, generar errores y advertencias, identificar y mostrar deprecaciones, y almacenar métricas.