Design de directives
As directives desempenham um papel importante: permitem implementar as funcionalidades que não são suportadas nativamente pela especificação GraphQL ou pelo próprio servidor GraphQL. As directives podem, assim, preencher essa lacuna funcional, para que a API consiga atender aos seus requisitos, sejam eles conhecidos ou desconhecidos.
Por esse motivo, as directives são um elemento extremamente importante nas fundações do servidor GraphQL. O Gato GraphQL se baseia em um design arquitetural sólido e robusto para as directives, o que o torna ao mesmo tempo extensível e poderoso.
Funcionalidade de baixo nível
Como decisão de design, o motor depende diretamente do pipeline de directives para resolver a query. Por esse motivo, as directives são tratadas como componentes de baixo nível, com acesso ao objeto onde a resposta é armazenada.
Como resultado, qualquer directive personalizada tem o poder de modificar a resposta GraphQL.
Um caso de uso evidente é a directive @remove, que permite indicar na query se preferimos omitir a resposta de um campo em vez de receber um valor null (existe uma issue na especificação relacionada a essa funcionalidade).
Chamadas eficientes às directives
As directives recebem todos os seus objetos e campos afetados juntos, em uma única execução.
Por exemplo, a chamada à API do Google Translate deve ser feita o menor número de vezes possível. Nesta query, ela é chamada apenas uma vez, contendo 10 trechos de texto para traduzir (2 campos, title e 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")
}
}Nesta query há 3 chamadas à API, uma para cada idioma (espanhol, francês e alemão), 10 strings cada, todas as chamadas são concorrentes:
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")
}
}Assinatura da função
Esta é a interface de directive de campo. Observe os parâmetros que a função resolveDirective recebe:
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;Esses parâmetros evidenciam a natureza de baixo nível da directive:
$idFieldSet: a lista de IDs por campo a serem processados pela directive$succeedingPipelineIDFieldSet: a lista de IDs por campo a serem processados pelas directives em uma etapa posterior do pipeline$resolvedIDFieldValues: o objeto de resposta
Os demais parâmetros permitem: acessar as variáveis da query e definir variáveis dinâmicas, passar mensagens com dados personalizados entre as directives, gerar erros e avisos, identificar e exibir depreciações, e armazenar métricas.