TypeORM同一Resolver内如何调用需context参数的其他Mutation
TypeORM Resolver 跨Mutation调用解决方案
直接调用的实现方式
你要调用的addNote方法的第一个参数是框架注入的Context对象,你在updateNote中已经通过@Ctx()装饰器拿到了该对象,手动传入即可,修改后的代码如下:
@Mutation() async updateNote( @Ctx() { req }: Context, @Arg('text', _type => string, { nullable: true }) text: string @Arg('noteId', _type => Int, { nullable: true }) noteId: Int ) { // ...原有逻辑 if (noteDoesNotExist) { // 手动构造addNote需要的context参数传入即可 return this.addNote({ req }, text) } // ...原有逻辑 }
跨Mutation调用的合理性说明
这种做法不属于完全禁用的范畴,但不是最佳实践,存在以下明显缺陷:
- 装饰器逻辑失效:只有框架触发的Mutation调用才会执行
@Mutation相关的拦截逻辑(比如参数校验、权限校验、日志埋点等),手动调用属于普通函数调用,不会触发这些逻辑,容易出现隐式漏洞。 - 复用层级不合理:Mutation属于接口层入口,仅负责处理外部请求的参数解析、上下文转换,核心业务逻辑应该下沉到Service层,复用逻辑应该在Service层完成,而非接口层。
- 事务管理困难:跨Mutation调用很难统一管控事务,如果新增和修改操作需要在同一事务内执行,这种写法无法实现。
长期优化方案
建议将核心业务逻辑抽离到独立的Service层,两个Mutation都调用Service层的方法实现复用,示例如下:
// 业务逻辑层 @Injectable() export class NoteService { constructor(private readonly noteRepository: Repository<Note>) {} async add(userId: number, text: string) { const note = this.noteRepository.create({ userId, text }) return this.noteRepository.save(note) } async upsert(userId: number, noteId: number, text: string) { const note = await this.noteRepository.findOneBy({ id: noteId, userId }) if (!note) { return this.add(userId, text) } note.text = text return this.noteRepository.save(note) } } // 接口层 @Resolver() export class NoteResolver { constructor(private readonly noteService: NoteService) {} @Mutation() async addNote( @Ctx() { req }: Context, @Arg('text', _type => string, { nullable: true }) text: string ) { const userId = req.user.id return this.noteService.add(userId, text) } @Mutation() async updateNote( @Ctx() { req }: Context, @Arg('text', _type => string, { nullable: true }) text: string @Arg('noteId', _type => Int, { nullable: true }) noteId: Int ) { const userId = req.user.id return this.noteService.upsert(userId, noteId, text) } }
这种写法结构更清晰,后续修改业务逻辑仅需调整Service层代码,也能方便的接入事务、统一校验等能力。
内容的提问来源于stack exchange,提问作者HigoChumbo
相关产品推荐
相关产品推荐

