본문 바로가기
Node.js

[NestJS] Configuration 설정 & TypeORM 연결

by WhoamixZerOne 2023. 5. 31.

https://www.linkedin.com/pulse/why-you-should-start-using-nest-js-yaman-alashqar

✔ 필요한 종속성 설치

Configuration과 TypeORM을 사용하기 위해서 Dependency를 설치해야 한다.

$ npm i --save @nestjs/config
$ npm i --save @nestjs/typeorm typeorm mysql2
@nestjs/config 패키지는 내부적으로 dotenv를 사용한다.
@nestjs/config 패키지를 사용하기 위해선 TypeScript 4.1 이상이 필요하다.

 

✔ TypeORM 연결

NestJS에서 TypeORM을 연결하는 방법은 여러 방법이 존재한다.

  • AppModule의 TypeOrmModule.forRoot에 직접 주입
  • json 파일 설정
  • ts 파일 객체에 설정 후 Root 인수에 객체 주입
  • ConfigService 사용

1. 직접 주입

AppModule에서 TypeOrmModule.forRoot()에 필요한 옵션 값을 넣어주면 된다.

// src/app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [    
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'user',
      password: '1234',
      database: 'db',      
      entities: [__dirname + '/../../**/**/*.entity.{js,ts}'],
      charset: 'utf8mb4_unicode_ci',
      synchronize: true,
      logging: true,
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

2. json 파일 설정

프로젝트 root 경로에 ormconfig.json에 파일을 생성한 뒤 필요한 옵션 값을 넣어주면 된다.

그리고 AppModule에 TypeOrmModule.forRoot()를 사용하면 자동으로 인식한다.

// project/ormconfig.json
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [TypeOrmModule.forRoot()],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

3. ts 파일 설정

필요한 옵션이 많다 보니 직접 주입하면 내용이 길어져서 따로 파일에 작성한다.

객체에 TypeOrmModuleOptions 타입으로 필요한 옵션 값을 넣어주면 된다.

// src/config/database.config.ts
import { TypeOrmModuleOptions } from '@nestjs/typeorm';

export const typeORMConfig: TypeOrmModuleOptions = {
  type: 'mysql',
  host: 'localhost',
  port: 3306
  username: 'user',
  password: '1234',
  database: 'db',
  entities: [__dirname + '/../**/*.entity.{js,ts}'],
  synchronize: true,
};

ts 파일을 설정했을 때 문제점은 위와 같이 설정하면 문제가 없지만 직접적으로 입력해 중요한 정보를 노출시키지는 않으므로

env 파일에 중요한 정보를 입력해서 process.env.value로 값을 불러올 것이다.

// src/config/database.config.ts
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
import { config } from 'dotenv';

config();

export const typeORMConfig: TypeOrmModuleOptions = {
  type: process.env.TYPE,
  host: process.env.MYSQL_HOST,
  port: process.env.MYSQL_PORT,
  username: process.env.MYSQL_USERNAME,
  password: process.env.MYSQL_PASSWORD,
  database: process.env.MYSQL_DATABASE,
  entities: [__dirname + '/../**/*.entity.{js,ts}'],
  synchronize: Boolean(process.env.MYSQL_SYNCHRONIZE),
  logging: Boolean(process.env.MYSQL_LOGGING),
};

하지만 위와 같이 설정을 하면 타입 에러를 만나게 된다...

"type"에 타입 에러는 "mysql | "mariadb" | "postgres" 등의 타입인데 "string"이라 에러가 나고,

"port"에는 "number" 타입인데 "string"이라 에러가 나고, 마찬가지로 "synchronize", "logging"도 난다.

// src/config/database.config.ts
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
import { config } from 'dotenv';

config();

export const typeORMConfig: TypeOrmModuleOptions = {
  type: 'mysql',
  host: process.env.MYSQL_HOST,
  port: +process.env.MYSQL_PORT,
  username: process.env.MYSQL_USERNAME,
  password: process.env.MYSQL_PASSWORD,
  database: process.env.MYSQL_DATABASE,
  entities: [__dirname + '/../**/*.entity.{js,ts}'],
  synchronize: Boolean(process.env.MYSQL_SYNCHRONIZE),
  logging: Boolean(process.env.MYSQL_LOGGING),
};

위와 같이 할 수는 있지만 좋은 방식은 아니라고 생각이 들어서 다음에 나오는 configService 방식으로 사용했다.

 

4. ConfigService 사용

Module, Service를 만들어서 사용하는 방법이다. 먼저 TypeOrm에 필요한 옵션 설정을 Service에 만들어준다.

여기서 중요한 점은 TypeOrmOptionsFactory 인터페이스의 createTypeOrmOptions() 메서드를 구현하는 것이고,

다른 하나는 생성자에 ConfigService 의존성을 주입하는 것이다.

이 의존성 주입으로 configService.get() 사용하여 env 파일의 값을 가져올 수 있다.

// src/config/database/typeorm.config.service.ts
import { Injectable } from '@nestjs/common';
import { TypeOrmModuleOptions, TypeOrmOptionsFactory } from '@nestjs/typeorm';
import { ConfigService } from '@nestjs/config';

@Injectable()
export class TypeOrmConfigService implements TypeOrmOptionsFactory {
  constructor(private readonly configService: ConfigService) {}

  createTypeOrmOptions(
    connectionName?: string,
  ): Promise<TypeOrmModuleOptions> | TypeOrmModuleOptions {
    return {
      type: 'mysql',
      host: this.configService.get<string>('MYSQL_HOST'),
      port: this.configService.get<number>('MYSQL_PORT'),
      username: this.configService.get<string>('MYSQL_USERNAME'),
      password: this.configService.get<string>('MYSQL_PASSWORD'),
      database: this.configService.get<string>('MYSQL_DATABASE'),
      entities: [__dirname + '/../../**/**/*.entity.{js,ts}'],
      charset: 'utf8mb4_unicode_ci',
      synchronize: this.configService.get<boolean>('MYSQL_SYNCHRONIZE'),
      logging: this.configService.get<boolean>('MYSQL_LOGGING'),
    };
  }
}

그리고 생성한 Service를 Module의 providers에 등록한다.

// src/config/database/typeorm.config.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmConfigService } from './typeorm.config.service';

@Module({
  providers: [TypeOrmConfigService],
})
export class TypeOrmConfigModule {}

마지막으로 생성한 Module을 AppModule에 등록해야 사용할 수 있다.

여기서 중요한 점은 ConfigService를 사용하기 위해서는 ConfigModule.forRoot() 등록해줘야 한다.

그리고 TypeOrmModule.forRootAsync()에 위에 만들어 놓은 Module, Service를 등록한다.

  • ConfigModule.forRoot({ isGlobal: true })에 isGlobal은 전역에서 사용할 수 있도록 하는 설정
  • TypeOrmModule.forRootAsync()는 데이터베이스 연결을 위한 옵션들을 비동기적으로 설정
    • imports, inject는 필요한 의존성을 주입
// src/app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AuthModule } from './auth/auth.module';
import { UsersModule } from './users/users.module';
import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm';
import { TypeOrmConfigModule } from './config/database/typeorm.config.module';
import { TypeOrmConfigService } from './config/database/typeorm.config.service';

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true }),
    TypeOrmModule.forRootAsync({
      imports: [TypeOrmConfigModule],
      useClass: TypeOrmConfigService,
      inject: [TypeOrmConfigService],
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

 

Async에 대한 NestJS 공식 문서 내용은 아래서 확인
NestJS - Async

이외에 다른 방식으로 설정을 할 수 있는데 방법이 너무 많은 것 같다...
Spring에서 사용하는 yaml방식도 가능한다.
yaml에 대한 NestJS 공식 문서 내용은 아래서 확인
NestJS - yaml

향로님의 Github에서 본 Class로 인스턴스를 생성해서 사용하는 방법도 있다.
향로님 github - database.config

 

 

🔗 Reference

'Node.js' 카테고리의 다른 글

[NestJS] Jest 단위 테스트 Mock  (0) 2023.07.22
[NestJS] Passport JWT 토큰 인증 구현 & 에러 핸들링  (1) 2023.07.06
Node.js 구조 & 동작 원리  (0) 2022.08.17
Node.js 교과서 4주차  (0) 2022.06.09
Node.js 교과서 3주차  (0) 2022.06.01

댓글