우당탕탕 우리네 개발생활

[Nestjs] 간단하게 사용하는 Nestjs Configuration 본문

tech

[Nestjs] 간단하게 사용하는 Nestjs Configuration

미스터카멜레온 2023. 11. 9. 17:57
Externally defined environment variables are visible inside Node.js through the process.env global. We could try to solve the problem of multiple environments by setting the environment variables separately in each environment. This can quickly get unwieldy, especially in the development and testing environments where these values need to be easily mocked and/or changed.

https://docs.nestjs.com/techniques/configuration

 

Documentation | NestJS - A progressive Node.js framework

Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Rea

docs.nestjs.com

 

위 글귀는 nestjs 공식 홈페이지에 있는 nestjs configuration이 탄생하게 된 선배개발자분들의 고민이라고 할 수 있습니다.

 

서버는 특정 목적을 위해 분류가 나눠집니다. 실서비스를 위해 사용되는 production서버, production을 위해 유사한 환경으로 구성하거나 실제로 업데이트된 코드들을 시험해 보기 위해 사용되는 development서버 등 원하는 대로 목적에 따라 분류를 나눌 수 있습니다. 각 서버들은 서버구동을 위한 config요소들을 갖게 됩니다. 목적에 따라 나뉜 서버들은 공통된 config요소들을 가질 수도 있지만 다양한 이유로 인해 요소명은 같지만 내용물은 다른 요소들을 가져야 할 때도 있습니다.(예를 들면, 데이터베이스의 경우 운영, 개발 목적에 따라 다르게 구성하는 경우가 있기 때문에 '접속정보' 등이 달라야만 합니다.) 상황에 따라 그에 맞는 configuration을 적용해야 하는데 공식사이트에 보면 nestjs configuration은 이를 다루는 데 용이하다고 얘기하고 있습니다.

 

https://github.com/mmmmicha/newsfeed.api 

 

GitHub - mmmmicha/newsfeed.api

Contribute to mmmmicha/newsfeed.api development by creating an account on GitHub.

github.com

 

기존에 dotenv라이브러리를 통해 configuration을 사용하던 제가, 사용해 본 가장 간단한 nestjs configuration 사용방법을 소개드리려고 합니다.(참고로 nestjs configuration은 dotenv를 내장하고 있습니다.) 아래 설명은 제가 작성했던 위 코드를 기반으로 설명드리겠습니다. 추가적인 nestjs configuration설명에 대한 디테일은 공식사이트를 통해 확인하시면 되겠습니다. 

 

1. nestjs configuration 라이브러리를 설치합니다.

npm i --save @nestjs/config

 

2. app.module.ts 파일 내 forRoot를 설정합니다.

// app.module.ts

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserModule } from './user/user.module';
import { AuthModule } from './auth/auth.module';
import { MongooseModule } from '@nestjs/mongoose';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { PageModule } from './page/page.module';
import { NewsModule } from './news/news.module';
import { SubscriptionModule } from './subscription/subscription.module';

@Module({
    imports: [MongooseModule.forRootAsync({
        imports: [ConfigModule],
        inject: [ConfigService],
        useFactory: async (configService: ConfigService) => ({
            uri: configService.get<string>('MONGO_URI'),
            dbName: configService.get<string>('MONGO_DB')
        })
    }), 
    // 이 부분입니다. ---------------------------------------------
    ConfigModule.forRoot({
        isGlobal: true,
    }), 
    // ---------------------------------------------------------
    UserModule, 
    AuthModule, PageModule, NewsModule, SubscriptionModule],
    controllers: [AppController],
    providers: [AppService],
})
export class AppModule {}

 

위 코드처럼 forRoot 내 isGlobal을 true로 설정해줘야만 전역적으로 nestjs configuration을 사용하실 수 있습니다.

 

때마침 좋은 사용예시가 있어 추가로 설명드리자면, nestjs에서 사용하게 되는 다양한 module컴포넌트들은 .forRootSync(), .forFeatureSync()라는 함수들을 가지고 있습니다. 이 함수들은 options를 파라미터로 받게 되는데, 그 옵션에 imports, inject가 있습니다. 이 부분에 ConfigModule과 ConfigService를 쓸 수 있어 기존 dotenv를 사용하던 분들은 좀 더 유동적으로 nestjs configuration을 사용하실 수 있겠습니다. 위 예시에서는 MongooseModule을. forRootSync()를 통해 설정하고 이 안에 nestjs configuration을 사용하고 있습니다.

 

3. 특정 module에 Nestjs configuration사용해 봅니다

// .env

ACCESS_TOKEN_SECRET=<YOUR_ACCESS_TOKEN_SECRET>
REFRESH_TOKEN_SECRET=<YOUR_REFRESH_TOKEN_SECRET>
// auth.service.ts

@Injectable()
export class AuthService {
    constructor(
        @InjectModel(User.name) private readonly userModel: Model<UserDocument>,
        private jwtService: JwtService,
        private configService: ConfigService
    ) {}

	...

    private createAccessToken(payload: Payload): string {
        return this.jwtService.sign(payload, {
            secret: this.configService.get<string>('ACCESS_TOKEN_SECRET'),
            expiresIn: '1h',
        })
    };

    private async createRefreshToken(payload: Payload): Promise<string> {
        const refreshToken = this.jwtService.sign(payload, {
            secret: this.configService.get<string>('REFRESH_TOKEN_SECRET'),
            expiresIn: "30d",
        });

        await this.updateRefreshTokenToUser(payload.userId, refreshToken);

        return refreshToken;
    }

    	...
    
}

 

nestjs의 철학대로 ConfigService를 auth.service.ts 내 constructor를 통해 inject(주입)했습니다. 이 service에 있는 get() 함수를 통해. env파일 안에 있는 ACCESS_TOKEN_SECRET과 REFRESH_TOKEN_SECRET을 정상적으로 불러오게 됩니다. 

 

간단한 서버를 작성하면서 사용했던 nestjs configuration을 공유했습니다. 앞서 얘기한 대로 nestjs configuration의 진가는 다양한 환경에 대한 configuration을 동적으로 처리하는 데 있습니다. 공식사이트를 통해 이 방법도 공부해 보시길 권장드리겠습니다.

 

감사합니다.