NestJS中ObjectType作为其他ObjectType字段时是否执行其解析器?
NestJS中嵌套ObjectType时,子类型解析器为何不执行?
场景复现
父ObjectType定义
@ObjectType() @KeyFields('id') // 用于生成联邦指令的封装器 export class MyInterestingThing { @Field(type => ID) id: string; @Field() someField: string; @Field(type => SomeDetails) someDetails: SomeDetails; }
子ObjectType定义
@ObjectType() export class SomeDetails { @Field() name: string; @Field(type => ID) id: string }
父解析器
@Resolver(of => MyInterestingThing) export class MyInterestingThingResolver { constructor(private readonly loader: MyInterestingThingLoader) {} @ResolveField(type => SomeDetails) async someDetails(@Parent() parent) { return { ...parent } } @ResolveReference() async resolveReference(ref: { __typename: string, id: string }) { return this.loader.byId.load(id); } }
子解析器
@Resolver(of => SomeDetails) export class SomeDetailsResolver { constructor(private readonly detailLoader: SomeDetailLoader) {} @ResolveField() async name(@Parent() { someDetailId }) { const ref = await this.detailLoader.byId.load(someDetailId); return ref.name; } @ResolveField() async id(@Parent() { someDetailId }) { const ref = await this.detailLoader.byId.load(someDetailId); return ref.id; } }
查询语句
{ myInterestingThing { someField someDetails { name id } } }
问题现象
执行上述查询时,父解析器正常执行,但子解析器SomeDetailsResolver中的name和id解析方法从未触发。期望每个ObjectType的解析器都能独立执行,实现关注点分离,但实际不符合预期。
原因分析与解决方案
核心原因
GraphQL的解析逻辑是:如果某个字段已经被父级解析器返回了具体值,就不会再调用对应子类型的字段解析器。具体到你的代码:
- 父解析器的
someDetails方法返回了{ ...parent },如果parent对象本身包含name和id字段,GraphQL会直接使用这些值,跳过子解析器的@ResolveField方法。 - 如果
parent对象里没有name和id,但也没有someDetailId字段,子解析器的@Parent() { someDetailId }会拿到undefined,导致加载逻辑无法执行,且因为没有抛出异常,你可能误以为解析器没被调用。
解决方案
方案1:父解析器仅返回子类型的标识字段
修改父解析器的someDetails方法,只返回子类型需要的标识(比如someDetailId),不返回name和id:
@ResolveField(type => SomeDetails) async someDetails(@Parent() parent) { return { someDetailId: parent.someDetailId }; // 仅传递子解析器需要的标识 }
这样当GraphQL解析someDetails的name和id字段时,会自动调用SomeDetailsResolver中对应的解析方法,通过someDetailId加载数据。
方案2:确保父级不返回子字段的值
如果父级必须返回someDetails的部分字段,但仍希望子解析器处理特定字段,需确保父级返回的对象中不包含该字段。不过更推荐方案1,保持关注点分离。
注意事项
- 必须保证父解析器返回的
someDetails对象包含子解析器需要的someDetailId字段,否则子解析器无法获取加载数据的标识。 - 子解析器的
@ResolveField方法只会在对应字段未被父级返回值填充时触发,这是GraphQL的标准解析行为,并非NestJS的特殊限制。
内容的提问来源于stack exchange,提问作者Ryan Shohoney
相关产品推荐
相关产品推荐

