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
메서드를 사용해야 했다. 이렇게 메서드들이 분리된 이유는 다음과 같았다.
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는 다음과 같다. 동작원리는 다음과 같다.
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;
},
};
정리하고 나니 간단해 보이는데, 또 한시간동안 고생했다.
(아무튼 해결해서 기쁜 마음에 포스팅)