NestJS 에서 TypeORM 적용해보기

김영훈·2024년 12월 1일

NestJS

목록 보기
5/9
post-thumbnail

📌Validation PipeLine 적용하기

✏️ main.js 내용 추가

import { NestFactory } from '@nestjs/core';  
import { AppModule } from './app.module';  
import { ValidationPipe } from '@nestjs/common';  
  
async function bootstrap() {  
  const app = await NestFactory.create(AppModule);  
  await app.listen(process.env.PORT ?? 3001);  
}  
  
bootstrap();

import { NestFactory } from '@nestjs/core';  
import { AppModule } from './app.module';  
import { ValidationPipe } from '@nestjs/common';  
  
async function bootstrap() {  
  const app = await NestFactory.create(AppModule);  
  app.useGlobalPipes(  
    new ValidationPipe({  
      whitelist: true,  
      forbidNonWhitelisted: true,  
    }),  
  );  
  await app.listen(process.env.PORT ?? 3001);  
}  
  
bootstrap();

✏️ app.useGlobalPipes 를 통해 validationPipe 설정

  • whitelist : dto 에 정의되지 않은값이 입력되면 무시한다.
  • forbidNonWhitelisted : 정의되지 않은값이 입력되면 에러를 발생


📌DB 환경설정

✏️ .env 파일 생성

# dev = 개발  
# prod = 배포  
ENV=dev  
  
# DB  
DB_TYPE=postgres  
DB_HOST=localhost  
DB_PORT=5432  
DB_USERNAME=myuser  
DB_PASSWORD=mypassword  
DB_DATABASE=mydatabase


📌app.module.ts 작성

//app.module.ts
@Module({  
  imports: [  
    ConfigModule.forRoot({  
      isGlobal: true,  
      validationSchema: Joi.object({}),  
    }),  
    TypeOrmModule.forRootAsync({  
      useFactory: () => ({}),  
      inject: [],  
    }),  
    MovieModule,  
    DirectorModule,  
  ],  
})  
export class AppModule {}

✏️ ConfigModule.forRootTypeOrmModule 쪽을 작성할 예정이다.

  • isGlobal : ConfigModule 에 정의된 내용을 다른 모듈에서 편하게 사용할 수 있도록 하는 설정 (전역화)


📌Joi 를 통한 validataion 설정

import {Module} from '@nestjs/common';  
import {MovieModule} from './movie/movie.module';  
import {TypeOrmModule} from "@nestjs/typeorm";  
import {ConfigModule, ConfigService} from "@nestjs/config";  
import * as Joi from "joi";    
import {MovieDetail} from "./movie/entity/movie-detail.entity";  
import { DirectorModule } from './director/director.module';  

//app.module.ts
@Module({  
  imports: [  
    ConfigModule.forRoot({  
      isGlobal: true,  
      validationSchema: Joi.object({
	      ENV: Joi.string().valid('env', 'prod').required(),
	      DB_TYPE: Joi.string().required(),
	      DB_HOST: Joi.string().required(),
	      DB_PORT: Joi.number().required(),
	      DB_USERNAME: Joi.string().required(),
	      DB_PASSWORD: Joi.string().required(),
	      DB_DATABASE: Joi.string().required()
      }),  
    }),  
    TypeOrmModule.forRootAsync({  
      useFactory: () => ({}),  
      inject: [],  
    }),  
    MovieModule,  
    DirectorModule,  
  ],  
})  
export class AppModule {}


📌TypeOrmModule 설정

import {Module} from '@nestjs/common';  
import {MovieModule} from './movie/movie.module';  
import {TypeOrmModule} from "@nestjs/typeorm";  
import {ConfigModule, ConfigService} from "@nestjs/config";  
import * as Joi from "joi";    
import {MovieDetail} from "./movie/entity/movie-detail.entity";  
import { DirectorModule } from './director/director.module';  

//app.module.ts
@Module({  
  imports: [  
    ConfigModule.forRoot({  
      isGlobal: true,  
      validationSchema: Joi.object({
	      ENV: Joi.string().valid('env', 'prod').required(),
	      DB_TYPE: Joi.string().required(),
	      DB_HOST: Joi.string().required(),
	      DB_PORT: Joi.number().required(),
	      DB_USERNAME: Joi.string().required(),
	      DB_PASSWORD: Joi.string().required(),
	      DB_DATABASE: Joi.string().required()
      }),  
    }),  
    TypeOrmModule.forRootAsync({  
      useFactory: (configService: ConfigService) => ({
	      type: configService.get<string>("DB_TYPE") as "mysql",
	      host: configService.get<string>("DB_HOST"),
	      port: configService.get<number>("DB_PORT"),
	      username: configService.get<string>("DB_USERNAME"),  
		  password: configService.get<string>("DB_PASSWORD"),  
		  database: configService.get<string>("DB_DATABASE"),
		  entities: [
			  Movie,
			  MovieDetail,
			  Director
		  ],
		  synchronize: true
      }),  
      inject: [ConfigService],  
    }),  
    MovieModule,  
    DirectorModule,  
  ],  
})  
export class AppModule {}

✏️ entities : 사용하는 엔티티들
synchronize : 애플리케이션 실행 시 데이터베이스 동기화 (프로덕션 환경엔 부적합)



📌Entity 설정

// director.entity.ts

import { BaseTime } from '../../common/entity/baseTime.entity';  
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';  
  
@Entity()  
export class Director extends BaseTime {  
  @PrimaryGeneratedColumn()  
  id: number;  
  
  @Column()  
  name: string;  
}

✏️ @Entity() 데코레이터를 사용하여 엔티티 선언을 할 수 있다.

// director.module.ts

import { Module } from '@nestjs/common';  
import { DirectorService } from './director.service';  
import { DirectorController } from './director.controller';  
import { TypeOrmModule } from '@nestjs/typeorm';  
import { Director } from './entity/director.entity';  
  
@Module({  
  imports: [TypeOrmModule.forFeature([Director])],  // Director 엔티티 레포지토리 주입
  controllers: [DirectorController],  
  providers: [DirectorService],  
})  
export class DirectorModule {}

✏️ TypeOrmModule.forFeature() 을 사용하여 특정 모듈에 엔티티를 주입할 수 있다.

mysql> show tables;
+----------------------+
| Tables_in_mydatabase |
+----------------------+
| director             |
| movie                |
+----------------------+
2 rows in set (0.00 sec)

✏️ pnpm start:dev 를 통해 실행하면 @Entity 선언한 테이블이 만들어지는 것을 알 수 있다.



번외) CLI 를 통한 RESTful API 쉽게 생성하기

$ nest g res
? What name would you like to use for this resource (plural, e.g., "users")? Movie
? What transport layer do you use? REST API
? Would you like to generate CRUD entry points? Yes

✏️ nest g resource 명령어를 통해 RESTful 방식으로 CRUD 에 필요한 템플릿을 얻을 수 있다.

0개의 댓글