架构指令设计
指令设计
指令扮演着重要的角色:它们可以实现 GraphQL 规范 或 GraphQL 服务器本身原生不支持的功能。指令可以填补功能上的空白,使 API 能够满足其已知或未知的需求。
因此,指令是 GraphQL 服务器基础架构中极为重要的元素。Gato GraphQL 采用了健全且坚固的指令架构设计,使其兼具可扩展性与强大功能。
底层功能
作为一项设计决策,引擎在解析 Query 时直接依赖指令管道。因此,指令被视为底层组件,可以访问存储响应的对象。
由此,任何自定义指令都有能力修改 GraphQL 响应。
一个典型的使用场景是 @remove 指令,它允许在 Query 中指定某个字段的响应是否应省略,而不是返回 null 值(规范中有一个关于此功能的 issue)。
高效的指令调用
指令会同时接收所有受影响的对象和字段,在单次执行中完成处理。
例如,调用 Google Translate API 的次数应尽可能少。在以下 Query 中,API 仅被调用一次,包含 10 段待翻译文本(5 篇文章的 2 个字段:title 和 excerpt):
query {
posts(pagination:{ limit: 5 }) {
title
excerpt
titleES: title @translate(from: "en", to: "es")
excerptES: excerpt @translate(from: "en", to: "es")
}
}在以下 Query 中,API 被调用 3 次,每种语言(西班牙语、法语和德语)各一次,每次包含 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:响应对象
其他参数则用于:访问 Query 变量并定义动态变量、在指令之间传递包含自定义数据的消息、触发错误和警告、识别并显示弃用信息,以及存储指标。
Next