2024. 4. 21. 13:47ㆍNestJS
NestJS를 사용하며 TypeORM을 사용하는 경우 설정할 때 이전에 했던 방식과 더 나은 방식을 기술할 예정입니다.
일단 TypeORM 설정을 파일로 따로 관리하여 AppModule에 Module decorator에 길게 관리하는 것을 싫어했습니다. 이에 아래와 같이 따로 파일로 관리하였습니다.
/// src/app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigModule } from '@nestjs/config';
import { typeORMConfig } from 'src/config/typeorm.config';
import { QuestionModule } from 'src/question/question.module';
import { AnswerModule } from 'src/answer/answer.module';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
}),
TypeOrmModule.forRoot(typeORMConfig),
QuestionModule,
AnswerModule,
],
controllers: [],
providers: [],
})
export class AppModule {}
/// src/config/typeorm.config.ts
import { ConfigService } from '@nestjs/config';
import 'dotenv/config';
import { TypeOrmModuleOptions } from "@nestjs/typeorm";
import { Answer } from 'src/entities/answer.entity';
import { Question } from 'src/entities/question.entity';
const config : ConfigService = new ConfigService();
export const typeORMConfig : TypeOrmModuleOptions = {
type: 'postgres',
host: config.get<string>('DATABASE_HOST'),
port: config.get<number>('DATABASE_PORT'),
username: config.get<string>('DATABASE_USERNAME'),
password: config.get<string>('DATABASE_PASSWORD'),
database: config.get<string>('DATABASE_DATABASE'),
entities: [Question, Answer],
synchronize : false,
keepConnectionAlive: true,
}
export const testTypeORMConfig : TypeOrmModuleOptions = {
type: 'postgres',
host: config.get<string>('TEST_DATABASE_HOST'),
port: config.get<number>('TEST_DATABASE_PORT'),
username: config.get<string>('TEST_DATABASE_USERNAME'),
password: config.get<string>('TEST_DATABASE_PASSWORD'),
database: config.get<string>('TEST_DATABASE_DATABASE'),
entities: [Question, Answer],
logging: true,
synchronize : true
}
NestJS는 내부적으로 IoC container를 이용하여 DI(의존성 주입)을 관리합니다. 위와 같은 방식을 사용한다면 외부에서 ConfigService를 생성하고 dotenv/config도 이용하기에 여러 번 환경변수가 load되는 것이 매우 불편하였습니다.
이러한 방식이 매우 불편하였기에 좀더 NestJS사용에 맞게 사용하고자 하였습니다.
TypeOrmModule.forRoot 대신 TypeOrmModule.forRootAsync로 교체하였으며 AppModule의 ConfigModule에서 config를 load하고 이후에 ConfigService를 주입하는 방식을 채택하였습니다.
/// src/app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { typeORMConfig } from 'src/config/typeorm.config';
import { QuestionModule } from 'src/question/question.module';
import { AnswerModule } from 'src/answer/answer.module';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
}),
TypeOrmModule.forRootAsync({
inject: [ConfigService],
useFactory: async (config: ConfigService) => await typeORMConfig(config)
}),
QuestionModule,
AnswerModule,
],
controllers: [],
providers: [],
})
export class AppModule {}
/// src/config/typeorm.config.ts
import { ConfigService } from '@nestjs/config';
import { TypeOrmModuleOptions } from "@nestjs/typeorm";
import { Answer } from 'src/entities/answer.entity';
import { Question } from 'src/entities/question.entity';
export const typeORMConfig = async (config: ConfigService): Promise<TypeOrmModuleOptions> => {
return {
type: 'postgres',
host: config.get<string>('DATABASE_HOST'),
port: config.get<number>('DATABASE_PORT'),
username: config.get<string>('DATABASE_USERNAME'),
password: config.get<string>('DATABASE_PASSWORD'),
database: config.get<string>('DATABASE_DATABASE'),
entities: [Question, Answer],
synchronize : false,
keepConnectionAlive: true,
}
};
export const testTypeORMConfig = async (config: ConfigService): Promise<TypeOrmModuleOptions> => {
return {
type: 'postgres',
host: config.get<string>('TEST_DATABASE_HOST'),
port: config.get<number>('TEST_DATABASE_PORT'),
username: config.get<string>('TEST_DATABASE_USERNAME'),
password: config.get<string>('TEST_DATABASE_PASSWORD'),
database: config.get<string>('TEST_DATABASE_DATABASE'),
entities: [Question, Answer],
logging: true,
synchronize : true
}
};
하지만 아직 불편한 점은 Entity를 정의할 때마다 TypeOrmModuleOptions 중 entities에 매번 추가 해줘야 한다는 것이 불편하여 그냥 알아서 해주길 바라기 때문에 경로를 통하여 entities를 사용할 수 있게 설정하였습니다. 경로는 build후의 경로에 js를 로드하는 방식으로 하였습니다. (만약 ts 경로를 하는 경우 코드상에 있는 경로들을 외부 경로로 인식하여 import하지 못하는 에러가 발생하는 이슈가 있었습니다... build후 실행되기에 생각해보면 당연한 이슈..)
/// src/config/typeorm.config.ts
import { ConfigService } from '@nestjs/config';
import { TypeOrmModuleOptions } from "@nestjs/typeorm";
export const typeORMConfig = async (config: ConfigService): Promise<TypeOrmModuleOptions> => {
return {
type: 'postgres',
host: config.get<string>('DATABASE_HOST'),
port: config.get<number>('DATABASE_PORT'),
username: config.get<string>('DATABASE_USERNAME'),
password: config.get<string>('DATABASE_PASSWORD'),
database: config.get<string>('DATABASE_DATABASE'),
entities: ['dist/entities/*.js'],
synchronize : false,
keepConnectionAlive: true,
}
};
export const testTypeORMConfig = async (config: ConfigService): Promise<TypeOrmModuleOptions> => {
return {
type: 'postgres',
host: config.get<string>('TEST_DATABASE_HOST'),
port: config.get<number>('TEST_DATABASE_PORT'),
username: config.get<string>('TEST_DATABASE_USERNAME'),
password: config.get<string>('TEST_DATABASE_PASSWORD'),
database: config.get<string>('TEST_DATABASE_DATABASE'),
entities: ['dist/entities/*.js'],
logging: true,
synchronize : true
}
};
옵션들을 좀더 NestJS과 TypeORM에게 할 일들을 맡기는 구조로 바뀌어 NestJS과 TypeORM을 동시 사용에 좀더 적합(?)하다는 견해입니다.
틀린 부분이 있을 수 있으니 알려주시면 감사하겠습니다 :)
'NestJS' 카테고리의 다른 글
[TypeORM] CLI 환경에서 Migration 하기 (with NestJS) (2) | 2024.06.16 |
---|---|
이슈 해결 - [TypeORM] DB migration file generate (2) | 2024.04.21 |