I have been delving into Nest.js and incorporating it into my project structure. Additionally, I have integrated TypeORM into the mix. The concept of Dependency Injection in Nest.js has me feeling a bit perplexed.
Project Structure
|-APP_MODULE
|-app.controller.ts
|-app.module.ts
|-app.service.ts
|-AUTH_MODULE
|-SIGN_UP_DTO
|-signup.dto.ts
|-auth.controller.ts
|-auth.module.ts
|-password-hash.service.ts
|-USER_MODULE
|-user.controller.ts
|-user.module.ts
|-user.service.ts
app.module.ts
@Module({
imports: [
UserModule,
ConfigModule.forRoot({
validationSchema: envValidationSchema,
validationOptions: {
allowUnknown: true,
abortEarly: true,
},
}),
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: async (configService: ConfigService) => ({
type: 'sqlite',
database: configService.getOrThrow('DATABASE_NAME'),
entities: [],
synchronize: configService.getOrThrow('DATABASE_SYNC_TABLES'),
autoLoadEntities: true,
}),
}),
PostModule,
CommonModule,
AuthModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
user.service.ts
@Injectable()
export class UserService {
constructor(
@InjectRepository(UserEntity)
private readonly userRepository: Repository<UserEntity>,
) {}
getAllUsers(): Promise<UserEntity[]> {
return this.userRepository.find();
}
getOneUserById(id: number) {
return this.userRepository.findOneBy({ id: id });
}
getOneUserByEmail(email: string) {
return this.userRepository.findOneBy({ email: email });
}
createUser(newUser: Partial<UserEntity>): Promise<UserEntity> {
return this.userRepository.save(newUser);
}
}
user.entity.ts
@Entity('users')
@Unique('user_email_unique', ['email'])
export class UserEntity {
@PrimaryGeneratedColumn()
id: number;
@Column()
email: string;
@Exclude()
@Column()
password: string;
@Column({ default: false })
isAdmin: boolean;
@Exclude()
@Column()
salt: string;
@OneToMany((type) => PostEntity, (post) => post.user)
posts: PostEntity[];
@CreateDateColumn()
created_at: Date;
@UpdateDateColumn()
updated_at: Date;
constructor(partial: Partial<UserEntity>) {
Object.assign(this, partial);
}
}
- Scenario - 1 (Not Working)
The export of user.service.ts from user.module.ts and its addition to the providers array in auth.module.ts results in an error message:
Nest can't resolve dependencies of the UserService (?). Please make sure that the argument UserEntityRepository at index [0] is available in the AuthModule context.
user.module.ts
@Module({
imports: [TypeOrmModule.forFeature([UserEntity])],
controllers: [UserController],
providers: [UserService],
exports: [UserService],
})
export class UserModule {}
auth.module.ts
@Module({
imports: [],
providers: [PasswordHashService, UserService], // -> Injecting UserService is giving error
exports: [],
controllers: [AuthController],
})
export class AuthModule {}
- Scenario 2 (working)
The export of password-hash.service.ts from auth.module.ts and its addition to the providers array in user.module.ts works seamlessly without any error.
user.module.ts
@Module({
imports: [TypeOrmModule.forFeature([UserEntity])],
controllers: [UserController],
providers: [UserService, PasswordHashService], // -> Injecting PasswordHashService(no error)
exports: [UserService],
})
export class UserModule {}
auth.module.ts
@Module({
imports: [],
providers: [PasswordHashService],
exports: [PasswordHashService],
controllers: [AuthController],
})
export class AuthModule {}
I require some clarification on the workings of DI in Nest.js.