Let’s say i have two entities:
// user.entity.ts
@ObjectType()
@Entity()
export class User {
@Field()
@PrimaryGeneratedColumn('uuid')
id: string;
@Field()
@Column({ unique: true })
username: string;
@Column({ select: false })
password: string;
@Field(() => [Task])
@OneToMany(() => Task, (task) => task.author)
authorOfTasks: Task[]
}
and
// task.entity.ts
@ObjectType()
@Entity()
export class Task {
@Field()
@PrimaryGeneratedColumn('uuid')
id: string;
@Field()
@Column()
title: string;
@Field()
@Column({ nullable: true })
description?: string;
@Field(() => User)
@ManyToOne(() => User, (user) => user.authorOfTasks)
author: User;
}
So in resolvers i need to resolve authorOfTasks
field in UserResolver
and author
field in TaskResolver
. To do this i need to inject UserService
and TaskService
in both UserResolver
and TaskResolver
. Like this:
// user.resolver.ts
@Resolver(of => User)
export class UserResolver {
constructor(
private userService: UserService,
private taskService: TaskService
) {}
// here are some queries that using userService
@ResolveField(() => [Task])
async authorOfTasks(
@Parent() author: User
) {
return this.taskService.getTasksByAuthor(author)
}
}
and
// task.resolver.ts
@Resolver()
export class TaskResolver {
constructor(
private taskService: TaskService,
private userService: UserService
) {}
// here are some queries that using taskService
@ResolveField(() => User)
async author(
@Parent() task: Task
) {
return this.userService.getUserById(task.author.id)
}
}
As you can see there are TaskService
and UserService
injected in both those resolvers and it ends up with Nest complaining about circular dependencies in my app and suggesting me to use forwardRef
to inject those dependencies. Ofcourse i can use that technique, but Nest documentation itself tells me that i should avoid circular dependencies when possible.
So my question is – what to do in this situation? Maybe i should reorganize my app somehow? How then? I want to keep my code modular as much as i can. My current structure looks like this:
Thank you! 🙏
4
1 Answer
While I do agree with @michel ‘s answer that circular dependencies are fairly common in GraphQL, I strongly disagree with the notion that one can "disable NestJS" warning for it.
The proper way for it would be to use forwardRef()
as mentioned in NestJS doc here. I too had a circular dependency problem when using NestJS and GraphQL and I resolved it at the Module level instead of Service level.
Circular references are quite common in GraphQL and perfectly fine – a parent object refers to an array of children and the child refers to the parent(s). This is a nest detail.
Jul 7 at 22:30
So basically i just need to omit Nest's suggestion of avoiding circular deps and go for forwardRef method?
Jul 8 at 9:37
Doesn't this circular dependency crash your tests? I receive the following error ` Cannot find module '@/user/entities' from 'tasks/entities/tasks.entity.ts'` when importing
import { User } from '@/user/entities';
and having the following property:@ManyToOne(() => User, (user) => user.casinoTokens) user: User;
Jul 11 at 9:47
Vitomir, i have not set up tests yet. It seems for me that this is path resolving problem, that is not related to my question. Probably you need to configure paths in
tsconfig.json
and/orjest.config.ts
Jul 12 at 11:10