I'm currently struggling with service injection in a guard.
Well, the thing is I made a JwtAuthGuard, that needs both my FirebaseService and my UserService.
So I thought it'd be useful to create a AuthGuardModule so i only need to import my AuthGuardModules in the modules that have a Controller, to use my Guard.
The thing is that unfortunately, i need this guard for my UserModule too.
So that's natural that i get a Circular Dependency Error When i import my AuthGuardModule in my UserModule.
Then, i tried all the things more or less related to Circular Dependency Error in Nest.js, but no can do.
Can someone tell me if:
- I am totally wrong thinking about making a module only for my guards ?
- If I'm not, how can I fix my
Circular Dependency Error? - If I misunderstood that part, why isn't it right and what's the best way to do so ?
JwtAuthGuard
@Injectable()
export class JwtAuthGuard implements CanActivate {
private readonly logger = new Logger(JwtAuthGuard.name)
constructor(
private readonly firebaseService: FirebaseService,
private readonly userService: UserService
) { }
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const token = request.headers['authorization'];
if (!token) {
throw new UnauthorizedException
}
try {
const firebaseUser = await this.firebaseService.getUserByToken(token)
request.user = await this.userService.getByEmail(firebaseUser.email)
return true
} catch (error) {
this.logger.error(this.canActivate.name, error)
throw new UnauthorizedException
}
}
}
AuthGuardModule
@Module({
imports: [UserModule],
providers: [FirebaseService, JwtAuthGuard],
exports: [JwtAuthGuard]
})
export class AuthGuardModule {}
EDIT
Well, jmcdo29 of the NestJS discord explained me that:
Your
AuthGuardModuleshould export theUserModuleand theFirebaseService. Guards, when used in the@UseGuards()decorator, are used in the context of the current controller's module, instead of being looked at as anInjectableprovider
So I did that way and it did solve my initial issue, but i have another circular dependency issue.
First, let's resume resume the architecture i have:
AuthModule
- It handles the routes for register, and the routes that send some emails like the password reset or the email verifying.
- It needs the
UserModuleto create a user into my db when i call the register route
@Module({
imports: [
AuthGuardModule
],
controllers: [AuthController],
providers: [AuthService, EmailService, FirebaseService],
})
export class AuthModule {}
FileModule
- It handles the file upload and deletion.
@Module({
imports: [
forwardRef(() => AuthGuardModule),
BlobModule,
MongooseModule.forFeature([{ name: File.name, schema: FileSchema }])
],
controllers: [FileController],
providers: [FileService],
exports: [FileService],
})
export class FileModule {}
UserModule
- It handles all the users routes.
- It needs the
FileModule, to check if the avatar exists when it's modified (i have only one route that updates all my users personal data) - It also needs the
AuthGuardModuleto use myJwtAuthGuard
@Module({
imports: [
forwardRef(() => AuthGuardModule),
forwardRef(() => FileModule),
MongooseModule.forFeature([{ name: User.name, schema: UserSchema }])
],
controllers: [UserController],
providers: [UserService, FirebaseService],
exports: [UserService, FileModule]
})
export class UserModule {}
AuthGuardsModule
- It contains my JWT check guard, and then i check if a user in my db is linked to the connected user
- It needs the
UserModuleto get the user in my db
@Module({
imports: [forwardRef(() => UserModule), FirebaseModule],
providers: [JwtAuthGuard, RegisterAuthGuard],
exports: [JwtAuthGuard, RegisterAuthGuard, FirebaseModule, UserModule]
})
export class AuthGuardModule {}
I could use firebase to store my users avatars and do it front side, but i have to store it in Azure Blob Storage (it's imposed to my), so the FileModule handle all that thing
So, now, that i solved my AuthGuardsModule -> UserModule circular dependecy thanks to you guys, i have a new circular dependency issue: AuthGuardsModule -> UserModule -> FileModule
I set a forwardRef of the AuthGuardsModule inside the FileModule but nest naturally said me that make sure that each side of a bidirectional relationships are decorated with "forwardRef()"
So i put a forwardRef to my FileModule import inside my UserModule, but same thing.
Any idea ?