“ 당신은 소프트웨어 품질을 추구할 수도 있고, 포인터 연산을 할 수도 있다. 그러나 두 개를 동시에 할 수는 없다. ”
지난 포스팅에서 TypeORM과 PostgreSQL에 대해서 알아봤습니다.
이번에는 NestJS에서 TypeORM을 활용하여 다루는 방법에 대해서 설명해 볼까 합니다.
혹시 이전 내용에 대해서 모르시다면 아래 링크를 통해 읽어보시면 좋을 거 같습니다.
모듈 설치
- pg: 8.11.2
- typeorm : 0.3.17
- @nestjs/typeorm : 10.0.0
- class-transformer : 0.5.1
- class-validator : 0.14.0
npm install pg typeorm @nestjs/typeorm --save
npm install class-validator class-transformer --save
TypeORM 설정 파일 생성
NestJS 프로젝트 src 폴더에서 database 폴더를 하나 생성합니다. 그리고 typeorm.config.ts 파일도 생성합니다.
각 옵션에 대한 설명은 주석으로 작성했으니 참고하시면 됩니다. 이전 포스팅에서 환경설정 한 데로 데이터베이스는
postgreSQL로 해서 설정하겠습니다.
// TODO: src/database/typeorm.config.ts
import { TypeOrmModuleOptions, TypeOrmOptionsFactory } from '@nestjs/typeorm'
import { Injectable } from '@nestjs/common'
@Injectable()
export class TypeormConfig implements TypeOrmOptionsFactory {
createTypeOrmOptions(): TypeOrmModuleOptions {
return {
type: 'postgres', // TODO: 데이터베이스 종류
url: '', // TODO: ex) postgresql://username:password@hostname:port/database
host: 'localhost', // TODO: 데이터베이스 서버 호스트
port: 5432, // TODO: 데이터베이스 포트
username: 'postgres',
password: 'postgres',
database: 'board-app', // TODO: 연결할 데이터베이스 이름
synchronize: true, // TODO: 스키마 자동 동기화 (production에서는 false)
dropSchema: false, // TODO: 애플리케이션 실행시 기존 스키마 삭제 여부
keepConnectionAlive: true, // TODO: 애플리케이션 재시작 시 연결 유지
logging: true, // TODO: 데이터베이스 쿼리 로깅 여부
entities: [__dirname + '/../**/*.entity{.ts,.js}'], //TODO: 중요! 엔티티 클래스 경로
extra: {
max: 100
}
} as TypeOrmModuleOptions
}
}
entities 설정할 때 [__dirname + '/../**/*. entity {. ts,. js}'] 이 설정으로 적용 시 에러가 나올 때가 있는데 그렇다면 직접 entity 클래스를 직접 삽입해 주시면 됩니다. 예를 들어서 BoardEntity라고 하면 entities: [BoardEntity] 이런 식으로 구현한 Entity클래스를 전부 삽입해 주시면 됩니다. 물론 저 설정이 적용이 되지 않으면 이렇게 해주시면 됩니다. 현재 제가 테스트했을 때는 잘 작동했으니 한번 따라서 해보시길 바랍니다.
TypeORM 설정 파일 연결
위에 typeorm.config.ts를 다 작성하셨으면 이제 src 폴더에 있는 app.module.ts에 설정파일을 등록합니다.
// TODO: src/app.module.ts
import { Module } from '@nestjs/common'
import { TypeOrmModule } from '@nestjs/typeorm'
import { DataSource, DataSourceOptions } from 'typeorm'
import { TypeormConfig } from './database/typeorm.config'
@Module({
imports: [
TypeOrmModule.forRootAsync({
useClass: TypeormConfig, // TODO: typeorm 설정한 클래스
dataSourceFactory: async (options: DataSourceOptions) => {
return new DataSource(options).initialize()
}
}),
]
})
export class AppModule {}
Boards 스캐폴딩
먼저 Board에 관련된 구성 요소들을 생성하겠습니다. CLI 명령어를 사용하면 간단하게 생성할 수 있습니다.
각 명령어로 구성요소를 생성하게 되면 생성하는 이름의 폴더가 생성이 되고 이 폴더 안에는 관련된 파일이 포함이 됩니다.
// TODO: Module 생성
npm g module boards
// TODO: Controller 생성
npm g controller boards
// TODO: Service 생성
npm g service boards
Board Entity 파일 생성
위에 명령어로 생성된 boards 폴더 안에서 board.entity.ts 파일을 생성합니다.
typeorm 설정에서 entities 설정에서 한 것처럼 *. entity 형식에 맞춰서 파일명을 지켜주세요.
아 먼저 BoardStatus라고 enum 파일을 하나 생성합니다. Board가 Public인지 Private인지 상태설정을 위함으로 사용합니다.
// TODO: boards/board-status-enum.ts
export enum BoardStatus {
PUBLIC = 'PUBLIC',
PRIVATE = 'PRIVATE'
}
entity 파일도 폴더하나 생성해서 구분 지어 줍니다.
// TODO: src/boards/entity/board.entity.ts
import { BaseEntity, Column, Entity, PrimaryGeneratedColumn } from 'typeorm'
import { BoardStatus } from '../board-status.enum'
@Entity()
export class Board extends BaseEntity {
@PrimaryGeneratedColumn()
id: number
@Column('varchar')
title: string
@Column('varchar')
description: string
@Column({ type: 'varchar', default: BoardStatus.PUBLIC })
status: BoardStatus
}
Board dto 파일 생성
boards 폴더 안에 dto 폴더를 생성하고 안에 create에서 사용할 create-board.dto.ts 파일을 생성합니다.
import { IsNotEmpty } from 'class-validator'
export class CreateBoardDto {
@IsNotEmpty()
title: string
@IsNotEmpty()
description: string
}
Boards Module 연결
board.module.ts파일로 오셔서 확인해 보시면 @Module 어노테이션 안에 controller든 Service든 설정이 자동으로 되어있는 것을 확인할 수 있습니다. 이제 여기에 typeorm module을 설정해 보겠습니다.
import { Module } from '@nestjs/common'
import { BoardsController } from './boards.controller'
import { BoardsService } from './boards.service'
import { TypeOrmModule } from '@nestjs/typeorm'
import { Board } from './entity/board.entity'
@Module({
imports: [TypeOrmModule.forFeature([Board])],
controllers: [BoardsController],
providers: [BoardsService]
})
export class BoardsModule {}
그리고 app.module로와서 board.module.ts를 연결합니다.
// TODO: src/app.module.ts
import { Module } from '@nestjs/common'
import { TypeOrmModule } from '@nestjs/typeorm'
import { DataSource, DataSourceOptions } from 'typeorm'
import { TypeormConfig } from './database/typeorm.config'
import { BoardsModule } from './boards/boards.module'
@Module({
imports: [
TypeOrmModule.forRootAsync({
useClass: TypeormConfig, // TODO: typeorm 설정한 클래스
dataSourceFactory: async (options: DataSourceOptions) => {
return new DataSource(options).initialize()
}
}),
BoardsModule //TODO: 추가
]
})
export class AppModule {}
이제 boards.module.ts에까지 설정이 완료가 되었다면 postgreSQL을 start 해주시고
nest start 또는 npm run start:dev로 실행하시면 아래와 같이 콘솔을 확인할 수 있습니다.
자 이제 pgAdmin으로 가셔서 board 테이블이 만들어졌는지 확인해 보겠습니다.
아래 board-app에 Schemas - public - Tables에서 확인하시면 됩니다.
Board 스캐폴딩으로 파일들을 구성하고 entity와 dto도 구성해 줬습니다. 그리고 typeorm에 Board entity를 연결하여 테이블을 구성했습니다. 다음에는 controller와 Service를 구성해 보면서 설명해야 하지만!.. 하기 전에 env 환경설정부터 진행하고 시작해 보겠습니다. 설정 옵션을 하드코딩하는 것보다 env파일로 구성해서 연결하는 게 깔끔하니 다음 포스팅에서 먼저 환경설정부터 진행하고 Controller와 Service에 대해서 설명해 보겠습니다.