Дизайн директив
Директивы играют важную роль: они позволяют реализовать те функции, которые не поддерживаются нативно спецификацией GraphQL или самим GraphQL-сервером. Таким образом, директивы помогают восполнить функциональные пробелы, чтобы API мог удовлетворять как известным, так и неизвестным требованиям.
По этой причине директивы являются крайне важным элементом в основе GraphQL-сервера. Gato GraphQL опирается на продуманный и надёжный архитектурный дизайн директив, который делает его одновременно расширяемым и мощным.
Низкоуровневая функциональность
Как архитектурное решение, движок напрямую зависит от конвейера директив при разрешении запроса. По этой причине директивы рассматриваются как низкоуровневые компоненты с доступом к объекту, в котором хранится ответ.
В результате любая пользовательская директива обладает возможностью изменять GraphQL-ответ.
Очевидным примером использования является директива @remove, которая позволяет указать в запросе, что лучше опустить ответ поля, чем получить значение null (в спецификации существует issue, касающийся этой функции).
Эффективные вызовы директив
Директивы получают все затронутые объекты и поля вместе, за одно выполнение.
Например, обращение к Google Translate API должно выполняться как можно реже. В этом запросе оно вызывается всего один раз, передавая 10 фрагментов текста для перевода (2 поля — title и excerpt — для 5 постов):
query {
posts(pagination:{ limit: 5 }) {
title
excerpt
titleES: title @translate(from: "en", to: "es")
excerptES: excerpt @translate(from: "en", to: "es")
}
}В этом запросе 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: объект ответа
Остальные параметры позволяют: получать доступ к переменным запроса и определять динамические переменные, передавать сообщения с пользовательскими данными между директивами, генерировать ошибки и предупреждения, выявлять и отображать устаревшие элементы, а также сохранять метрики.