NestJS의 DI 방법은 스프링과 비슷하면서도 사뭇 다르다. 자바스크립트의 module 개념도 친숙하지 않은 상황에서 DI를 적용시키다 많이 헤맸다. 그동안 이리저리 부딪히면서 깨달은 내용을 정리해본다.
1. DI 처리하기
constructor(private readonly catsService: CatsService) {}
이렇게 constructor에서 해당 데이터, 그러니까 여기선 CatsService의 인스턴스를 생성하고 리턴하면 NestJS가 알아서 resolve 해준다.
앞에서 말했듯 NestJS는 스프링처럼 annotation을 이용해 DI를 한다.
[auth.service.ts]
@Injectable()
export class AuthService {
constructor(
@Inject('JwtService') private readonly jwtService: JwtService,
@Inject('UserService') private readonly userService: UserServiceImpl,
@Inject('ValidationService') private readonly validationService: ValidationServiceImpl,
) {}
}
[user.service.impl.ts]
@Injectable()
export class UserServiceImpl implements UserService {
constructor(@InjectRepository(User) private userRepository: IUserRepository) {}
}
만약 interface처럼 implement하는 클래스가 많을 경우엔, 자동으로 어떤 클래스인지 찾아줄 수가 없으므로 위처럼 직접 지정해준다. 스트링으로 별칭을 지어주거나 User처럼 객체를 넣어줄 수 있다.
2. DI하려는 클래스를 Module에 Provider로 등록하기
위처럼 선언했다고 끝이 아니다. injection을 수행하려면 module에 등록해주어야 한다.
@Module({
controllers: [CatsController],
providers: [CatsService],
})
export class ApplicationModule {}
기본적으로는 providers 부분에 해당 클래스를 넣어주면 된다.
[auth.module.ts]
@Module({
imports: [
PassportModule.register({ defaultStrategy: 'jwt' }),
JwtModule.register({
secretOrKeyProvider: (
requestType: JwtSecretRequestType,
) => {
switch (requestType) {
case JwtSecretRequestType.SIGN:
return 'privateKey';
case JwtSecretRequestType.VERIFY:
return 'publicKey';
default:
return 'hard!to-guess_secret';
}
},
signOptions: {
expiresIn: 3600,
},
}),
UserModule],
providers: [AuthService,
{provide: 'UserService', useClass: UserServiceImpl},
{provide: 'ValidationService', useClass: ValidationServiceImpl},
{provide: 'IUserRepository', useClass: UserRepository},
{provide: 'BridgeService', useClass: Web3BridgeService},
{provide: 'WEB3', useClass: Web3},
],
controllers: [AuthController],
exports: [PassportModule],
})
export class AuthModule {
}
위에서는 provide와 useClass를 이용해 바인딩해주고 있다. 자세한 내용은 공식 docs의 Custom Provider를 참고하면 된다. 간단히 말하자면, 의존성 주입 시 특정한 클래스를 지정해주고 싶을 때 사용한다.
이때, provide는 @Inject가 있던 클래스에서 @inject('JwtService')의 괄호 안의 내용 즉, JwtService 부분을 넣어준다. 이때 주의할 점은,
- @inject('JwtService')처럼 string으로 별칭을 지정해줬다면 그대로 provide: 'JwtService'로 쓴다.
- @inject(User)처럼 객체 그대로를 넣었다면 그대로 provide: User 라고 넣어야 한다.
내가 여기서 잘못한 것
- repository는 위와 같이 사용하지 않고 그냥 클래스 자체로 선언해야 했다.
- 맨 위에 defaultStrategy로 jwt를 지정해놓고 그에 대한 내용을 import 하지 않았다.
[auth.module.ts]
@Module({
imports: [
PassportModule.register({ defaultStrategy: 'jwt' }),
JwtModule.register({
secretOrKeyProvider: (
requestType: JwtSecretRequestType,
) => {
switch (requestType) {
case JwtSecretRequestType.SIGN:
return 'privateKey';
case JwtSecretRequestType.VERIFY:
return 'publicKey';
default:
return 'hard!to-guess_secret';
}
},
signOptions: {
expiresIn: 3600,
},
}),
UserModule],
providers: [AuthService, UserRepository, JwtStrategy,
{provide: 'UserService', useClass: UserServiceImpl},
{provide: 'ValidationService', useClass: ValidationServiceImpl},
{provide: 'BridgeService', useClass: Web3BridgeService},
{provide: 'WEB3', useClass: Web3},
],
controllers: [AuthController],
exports: [PassportModule],
})
export class AuthModule {
}
이렇게 변경하면 정상적으로 작동한다.
맨 처음 NestJS를 접하고 같은 내용의 공식 문서를 읽을 땐 정말 무슨 말인지 하나도 와닿지가 않았는데 실제 프로젝트에서 부딪혀보고 다시 읽으니 '그게 그런 뜻이었구나' 하고 이해하게 되었다. 조금이지만 여전히 발전하고 있다!
'개발새발 개발자 > JavaScript' 카테고리의 다른 글
[NestJS] Promise 여부에 따른 test code에서의 throw 처리 방법 (0) | 2019.06.08 |
---|---|
[NestJs] Authentication 도전기 - 2 (feat.초보에겐 너무나 어려운 공식 문서) (0) | 2019.05.19 |
[NestJs] Authentication 도전기 - 1 (feat.초보에겐 너무나 어려운 공식 문서) (2) | 2019.05.17 |
[javascript] 스토리지 및 DOM 조작법 (0) | 2018.12.07 |
[Vue.js] router 정보 보기 (0) | 2018.12.07 |