[Nest.js] TypeORM 설정을 별도 파일로 관리하기

Donghun Seol·2023년 4월 17일
0

배경

app.module.ts에서 아래와 같이 orm설정하는 코드가 있다.

@Module({
  TypeOrmModule.forRoot({
        type: 'mysql',
        host: process.env.DATABASE_HOST,
        port: +process.env.DATABASE_PORT,
        username: process.env.DATABASE_USERNAME,
        password: process.env.DATABASE_PASSWORD,
        database: process.env.DATABASE_DB,
        entities: [__dirname + '/**/*.entity.{ts,js}'],
        synchronize: process.env.DATABASE_SYNCHRONIZE === 'true', // 서버 구동시 엔티티 기반으로 스키마를 변경하는 옵션이다.
      }),
})

forRoot메서드 안이 너무 복잡해서 안의 설정을 밖으로 빼고싶었다.

시도와 에러

나이브하게 설정 객체만 외부파일로 선언하고, forRoot 메서드에 해당 객체를 인자로 전달하는 방식으로 구현하니 작동하지 않았다. 외부 파일에서 설정을 읽어오기 위해서는 forRootAsync 메서드를 사용해야 했다. 이렇게 메서드들이 분리된 이유는 다음과 같았다.

  1. 외부 모듈이나 파일에 의존하지 않는 메서드는 즉시 디펜던시 설정이 가능하므로 간편하게 동기메서드를 사용한다.
  2. 비동기 메서드는 외부 모듈이나 서비스에 의존하는 경우 사용해야한다. 모듈이 설정완료되기 전에 의존하는 데이터 수신완료가 선결되어야 하기 때문이다. 비동기 메서드를 활용하면 http요청의 응답에 의존하는 모듈 설정도 가능하다.
  3. 따라서 간단한 설정의 경우 동기메서드를 사용하고 복잡하고 외부 의존도가 높은 경우 비동기 메서드를 사용한 모듈설정을 고려해볼 필요가 있다.

해결

app.module.ts는 다음과 같이 구성된다. 훨씬 가독성이 높아졌다.
(env파일을 읽어와 config 모듈 설정하는 부분도 코드에 포함시켰다.)

import { ormConfig } from 'config/ormConfig'

@Module({
  ConfigModule.forRoot({
      envFilePath: [`${__dirname}/config/env/.${process.env.NODE_ENV}.env`],
      load: [emailConfig, authConfig],
      isGlobal: true,
      validationSchema: validationSchema,
    }),

  TypeOrmModule.forRootAsync(ormConfig),
})

실제 설정이 담겨있는 ormConfig.ts는 다음과 같다. 동작원리는 다음과 같다.

  1. 네스트 런타임이 인스턴스화한 ConfigService를 주입받는다.
  2. ConfigService는 .env파일의 내용을 가지고 있다.
  3. useFactory에서 동적으로 옵션을 생성한다.
  4. 동적으로 생성되어 리턴된 옵션은 forRootAsync에 전달되어 ORM 설정을 완료한다.

ormConfig.ts

import { ConfigModule, ConfigService } from '@nestjs/config';
import { TypeOrmModuleAsyncOptions } from '@nestjs/typeorm';

export const ormConfig: TypeOrmModuleAsyncOptions = {
  imports: [ConfigModule],
  inject: [ConfigService],
  useFactory: async (configService: ConfigService) => {
    const option = {
      type: configService.get('DATABASE_TYPE'),
      host: configService.get('DATABASE_HOST'),
      port: configService.get('DATABASE_PORT'),
      username: configService.get('DATABASE_USERNAME'),
      password: configService.get('DATABASE_PASSWORD'),
      database: configService.get('DATABASE_DB'),
      synchronize: true,
      entities: ['dist/**/*.entity{.ts,.js}'],
    };

    return option;
  },
};

정리하고 나니 간단해 보이는데, 또 한시간동안 고생했다.
(아무튼 해결해서 기쁜 마음에 포스팅)

레퍼런스

https://github.com/kakasoo/nestjs-e-commerce-example/

profile
I'm going from failure to failure without losing enthusiasm

0개의 댓글