2023. 2. 24. 07:27ㆍ프로젝트/8주차 실전 프로젝트
1. Github Issue
https://github.com/TeamBudgetOverflow/backend/issues/57
refactoring: using ConfigModule instead process.env · Issue #57 · TeamBudgetOverflow/backend
환경 변수를 가져오는 process.env는 Node.js의 기능으로, Nest.js 사용시에도 환경 변수에 액세스하는 올바른 방법은 맞습니다. 그러나 이미 우리는 ConfigModule을 import하여 전역으로 사용하고 있고, 모
github.com
2. 계기
기존에는 크게 생각해보지 않았던 구문이었는데 Nest.js 강의를 듣고 모듈화에 대해서 다시 한번 생각해보게 되면서 알게 된 점입니다.
조사과정에서 Nest.js에서 process.env를 사용하는 것도 올바른 방법이지만, ConfigModule에서 환경변수에 대한 접근도 지원한다는 것을 알게되었다. 이미 기존에 ConfigModule을 사용하고 있었고(전역으로 slack config를 제공하고 있었다.) 기존의 process.env로 제공하던 환경변수를 ConfigModule과 통합하여 코드의 가독성을 높이고자 하였습니다.
3. 수정 내용
코드 전반적으로 사용하던 process.env를 사용하던 것을 전부 다 변경 했습니다. 변경하면서 몇 가지 사례만 소개하려 합니다.
적용 예시
configService.get<Type>('ENV_NAME')
<Type>는 Generic Type로 선택사항이지만 유형 안정성을 높이고 불일치 방지를 위해 사용하는 것이 좋습니다.
다음의 경우 TypeScript는 값이 Type로 변환되도록 하므로 잘못된 타입이 들어가있을 경우 발생할 문제를 피할 수 있습니다.
1. main.ts
코드를 수정하면서 제일 기억에 남았던 부분이라 생각합니다.
제가 알고 있는 모듈은 app 모듈에서 import되고 사용된다고 생각했기 때문에 main.ts에서는 적용이 안된다고 무심코 생각했던 것 같네요.
프로그램 실행 순서상 NestFactory로 AppModule이 실행 되고 초기화(ConfigModule또한 당연히)한 후에 app.get(ConfigService)되니 사실 이상할 건 없습니다.(당연한걸 신기하다고 보고 있었네요.)
import { ConfigService } from '@nestjs/config';
async function bootstrap() {
const app = await NestFactory.create(AppModule, {
logger: winstonLogger,
});
const configService = app.get(ConfigService);
app.enableCors({ origin: true, credentials: true });
const port = configService.get<number>('PORT', 3000); vv
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
}),
);
app.useGlobalFilters(new HttpExceptionFilter());
await app.listen(port);
console.log(`listening on port ${port}`);
}
bootstrap();
1. typeORM.config.ts
/src/configs/typeorm.config.ts
export async function getTypeOrmConfig(): Promise<TypeOrmModuleOptions> {
const configService = new ConfigService();
return {
type: 'mysql',
host: configService.get<string>('DB_END_POINT'),
port: configService.get<number>('DB_PORT'),
username: configService.get<string>('DB_USERNAME'),
password: configService.get<string>('DB_PASSWORD'),
database: configService.get<string>('DB_TESTDBNAME'),
...
}
/app.module.ts
imports: [
TypeOrmModule.forRootAsync({ useFactory: getTypeOrmConfig }),
...
2. kakao.strategy.ts
export class KakaoStrategy extends PassportStrategy(Strategy) {
constructor(private configService: ConfigService) {
super({
clientID: configService.get<string>('KAKAO_CLIENT_ID'),
clientSecret: configService.get<string>('KAKAO_CLIENT_SECRET'),
callbackURL: configService.get<string>('KAKAO_CALLBACK_URL'),
});
}
3. ~.service.ts
export class AuthService {
constructor(
private configService: ConfigService,
) {}
async tokenValidate(token: string) {
return await this.jwtService.verify(token, {
secret: this.configService.get<string>('ACCESS_TOKEN_KEY'),
});
}
...
4. 개선 효과 및 느낀점
사실 무언가 개선했다는 느낌은 잘 없었습니다. process.env와 ConfigModule을 선택하는 것은 애플리케이션의 요구 사항에 따라 다르다고 알고 있었기 때문입니다.
- process.env : 간단하고 이해하기 쉽지만 환경 변수가 많아지면 관리가 어려워질 수 있다.
- ConfigModule : 구조화된 구성을 정의할 수 있으므로 애플리케이션 전체에서 구성 값을 더 쉽게 관리하고 재사용 가능
ConfigModule을 기존에 사용하고 있었기 때문에 코드를 통합한다는 측면에선 개선이 되었다고 생각합니다. 그러나 무언가를 크게 개선했다! 라는 느낌은 없습니다.
대신에 다른 흥미로운 것을 발견했는데 AWS Systems Manager Parameter Store입니다.
해당 서비스는 DB 문자열 및 기타 중요한 정보와 같은 구성 데이터를 저장하고 검색하는 안전한 방법을 제공합니다. 구성 데이터를 한 위치에 중앙 집중화한 다음 애플리케이션에서 해당 데이터에 안전하게 액세스 할 수 있습니다.
좀 더 공부를 해봐야 겠지만(정확하지 않을 수 있음) .env로 사용되고 있는 환경 변수를 외부의 안전한 서버에 넣어두고 값을 가져와서 사용하는 것에 강렬한 흥미를 느꼈습니다.
아무래도 실행 서버와 같은 공간에 환경 변수를 두는 것은 위험하다고 생각했기 때문에 격리된 외부 공간에 보관하는 것은 좋은 방법이라 생각되었습니다.
추후 적용 및 실제로 사용해보고 나서 포스팅을 올려보겠습니다
'프로젝트 > 8주차 실전 프로젝트' 카테고리의 다른 글
| 3. 리펙토링 -Express 종속성 제거와 커스텀 데코레이터- (0) | 2023.02.24 |
|---|---|
| 3. 리펙토링 목록 (0) | 2023.02.24 |
| 2. 트러블 슈팅 -DTO Data & Data Type Transform- (0) | 2023.02.18 |
| 2. 트러블 슈팅 -소셜 로그인 OAuth 2.0- (0) | 2023.02.18 |
| 2. 트러블 슈팅 -연관 테이블- (0) | 2023.02.18 |