如何区分GraphQL resolver的客户端调用与Apollo联邦调用?
问题解答
完全可以在服务端区分普通查询和联邦查询两类调用,核心依据是Apollo联邦协议的底层实现特性:所有联邦查询请求到子服务时,都会触发固定的_entities根查询字段,和普通业务根查询完全隔离。
以下是适配你当前技术栈的两种实现方案:
方案1:全局插件统计(无侵入,无需修改现有业务代码)
利用Apollo Server的插件生命周期钩子,在字段解析阶段自动判断请求类型,适合全局统一做指标统计的场景:
- 编写统计插件,示例代码如下:
const queryMetricsPlugin = { requestDidStart() { return { willResolveField({ info }) { // 判断是否为联邦实体查询 const isFederationCall = info.parentType.name === 'Query' && info.fieldName === '_entities' if (isFederationCall) { // 可通过info.returnType.name拿到当前解析的实体名(如User、Profile)做细分统计 addFederationQueryCount(info.returnType.name) } // 判断是否为普通业务根查询/变更 else if (['Query', 'Mutation'].includes(info.parentType.name)) { // 可通过info.fieldName拿到当前查询的接口名做细分统计 addNormalQueryCount(info.fieldName) } } } } }
- 将插件注册到Apollo Server实例的
plugins配置项中即可全局生效。
方案2:Resolver层分别埋点(和DGS用法对应,粒度更灵活)
和你了解的DGS框架用法一一对应,TypeGraphQL+Apollo联邦栈有专门的装饰器区分两类Resolver:
- 普通业务查询用原生
@Query()装饰器,对应DGS的@DgsQuery - 联邦实体解析器用
@ResolveReference()装饰器,对应DGS的@DgsEntityFetcher
示例代码如下:
import { Resolver, Query, Arg } from 'type-graphql' import { ResolveReference } from '@apollo/federation' @Resolver(() => User) class UserResolver { // 普通查询埋点 @Query(() => User) async getUser(@Arg('id') id: string) { recordNormalQueryMetric('getUser') return userService.getById(id) } // 联邦查询埋点 @ResolveReference() async resolveUserRef(ref: { __typename: string; id: string }) { recordFederationQueryMetric('User') return userService.getById(ref.id) } }
注意事项
统计时只需在根查询或者@ResolveReference方法中计数一次即可,避免字段级解析重复触发统计逻辑导致计数不准。
内容的提问来源于stack exchange,提问作者Marc Pascual
相关产品推荐
相关产品推荐

