그래... 의존성 주입... 분명 자바에도 이런거 있었던거같은데...
해당 오류는 NestJS의 의존성 주입(Dependency Injection) 시스템에서 UserController 클래스에 필요한 의존성을 해결할 수 없다는 것을 나타냅니다. 구체적으로는 EmailService가 ApiRestModule 컨텍스트에서 사용 가능하지 않은 상태입니다.
이러한 오류를 해결하기 위해 다음과 같은 점검 사항들을 확인해 보세요:
- ApiRestModule이 올바른 NestJS 모듈인지 확인하세요: ApiRestModule 클래스가 정상적인 NestJS 모듈로 작성되어 있는지 확인합니다. @Module() 데코레이터를 사용하여 올바르게 설정되었고, 필요한 프로바이더(Provider)와 의존성 등록이 이루어져 있는지 다시 한번 검토합니다.
- EmailService가 현재의 ApiRestModule에 포함되어 있는지 확인하세요: EmailService가 현재의 ApiRestModule에서 제공자(Provider)로 등록되어 있는지 확인합니다. 즉, providers 배열 또는 exports 배열 내에 해당 서비스(EmailService)가 포함되어 있어야 합니다.
- 별도의 @Module에서 EmailService를 내보내고 현재의 ApiRestModule에서 가져오고 있는지 확인하세요: 만약 EmailService가 별도의 모듈(EmailModule)에서 정의되고 내보내진 경우, 해당 모듈(EmailModule)이 현재의 ApiRestModule 내부에서 임포트(import)되었는지 다시 한번 확인합니다.
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, FindOneOptions } from 'typeorm';
import { User } from '../../domains/entities/User.entity';
@Injectable()
export class EmailService {
constructor(
@InjectRepository(User)
private usersRepository: Repository<User>,
) {}
validateEmailFormat(email: string): boolean {
const emailRegex = /^[^\s@]+@[^\s@]+.[^\s@]+$/;
return emailRegex.test(email);
}
async checkDuplicateEmail(email: string): Promise<boolean> {
const options: FindOneOptions<User> = {
where: {
userEmail: email,
},
};
const existingUser = await this.usersRepository.findOne(options);
return !!existingUser;
}
}
EmailService라는 NestJS 서비스 클래스입니다. 이 클래스는 이메일 관련 기능을 수행하며, 주로 사용자 이메일의 유효성 검사와 중복 여부 확인을 담당합니다.
여기서 몇 가지 주요 포인트를 설명해 드리겠습니다:
- @Injectable(): EmailService 클래스에 @Injectable() 데코레이터가 지정되어 있습니다. 이를 통해 해당 클래스가 NestJS의 의존성 주입(Dependency Injection) 시스템에서 관리되는 서비스임을 나타냅니다.
- @InjectRepository(User): TypeORM의 Repository<User> 타입의 인스턴스를 주입받기 위해 @InjectRepository() 데코레이터가 사용되었습니다. 이를 통해 User 엔티티에 대한 Repository 객체(usersRepository)가 생성되고, 해당 객체를 통해 데이터베이스 조작이 가능해집니다.
- validateEmailFormat(email: string): boolean: 입력된 이메일 문자열(email)이 유효한 형식인지 확인하는 메서드입니다. 정규식(emailRegex)을 사용하여 유효성 검사를 수행하고, 결과로 boolean 값을 반환합니다.
- async checkDuplicateEmail(email: string): Promise<boolean>: 입력된 이메일 문자열(email)이 이미 데이터베이스에 존재하는 중복된 이메일인지 확인하는 메서드입니다. TypeORM의 findOne() 메서드를 사용하여 해당 이메일과 일치하는 사용자(User) 엔티티를 찾아옵니다. 찾아온 결과가 존재한다면 중복된 이메일로 간주하고 true 값을 반환합니다.
위 코드에서는 NestJS와 TypeORM을 활용하여 EmailService 클래스가 데이터베이스와 상호작용하며, 유효성 검사 및 중복 여부 확인과 같은 기능을 수행합니다.
@Module({
imports: [PassportModule],
providers: [EmailService], // EmailService를 providers 배열로 이동
controllers: [AuthController, UserController, MatchController, BillController, PlaceController],
})
export class ApiRestModule {}
컨트롤러야 그냥 컨트롤러 정의된거 때려 넣으면 되는데,
imports, providers 이거 구분 은근 헷갈려서 잘 살펴서 넣어야 한다. 안그럼
[Nest] 25564 - 2023. 10. 18. 오후 10:25:01 ERROR [ExceptionHandler] Classes annotated with @Injectable(), @Catch(), and @Controller() decorators must not appear in the "imports" array of a module. Please remove "EmailService" (including forwarded occurrences, if any) from all of the "imports" arrays.
Scope [AppModule -> ApiRestModule]
이렇게 오류난다... 여기서 삽질이 한 4~5번 정도 있었는데, 여기까지 고치고 나니 문득 드는 생각...
'근데 유저 리포지토리는...?'
후... 급하게 추가..
@Module({
imports: [PassportModule]
providers: [EmailService, UserRepository], // UserRepository 추가
controllers: [AuthController, UserController, MatchController, BillController, PlaceController],
})
export class ApiRestModule {}
이러면 이제 동작은 되는데, 저장하는데서 오류가 난다...
그렇게 삽질하길 몇 번 반복... 드디어 동작하고, 저장도 완벽하게 되는 올바른 코드는...
@Module({
imports: [TypeOrmModule.forFeature([User]), PassportModule],
providers: [EmailService],
controllers: [AuthController, UserController, MatchController, BillController, PlaceController],
})
export class ApiRestModule {}
이거였다고 한다.. 애초에 내가 쓰던 모듈이 TypeOrmModule 이었는데 이걸 import해주지 않았고,
유저 리포지토리라고 해서 냅다 유저 리포지토리 때려 넣는게 아니라..ㅋㅋ forFeature([User])를 써야 한다는 걸 알았다.
큰 깨달음을 얻고 가는 것 같다. 이로써 마지막으로 테스트만 해보면 끝...!
제발 테스트야 잘 되어줘,,,!