반응형
이번 시간에는 TypeORM 모듈을 이용해서 DB을 연결해서 간단한 게시판(Board 모듈) CRUD를 진행해 보도록 하겠습니다.
준비사항 : mysql DB
간단하게 docker를 이용해서 local에서 mysql 사용하고 싶으시다면 참고 하시면 좋을 것 같습니다.
docker-compose.yml
version: '3.1'
services:
db:
image: mysql
restart: always
command: --lower_case_table_names=1 # 대소문자 구분
container_name: mysql-db
environment:
- MYSQL_DATABASE=test
- MYSQL_ROOT_PASSWORD=1234
- TZ=Asia/Seoul
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
volumes:
- ./db:/var/lib/mysql # db 볼륨 처리
ports:
- 3306:3306
# docker-compose up -d
1. TypeORM 모듈 install
- 저는 mysql db를 사용하도록 하겠습니다.
- mysql과 typeorm 모듈을 설치합니다.
npm install mysql2 typeorm @nestjs/typeorm
2. TypeORM config 설정
config.typeorm.ts
import { TypeOrmModuleOptions } from "@nestjs/typeorm";
export const typeORMConfig : TypeOrmModuleOptions = {
type: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: '1234',
database: 'test',
entities: [__dirname+ '/../**/*.entity.{js,ts}'],
synchronize:true
}
app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { typeORMConfig } from './configs/config.typeorm';
@Module({
imports: [
TypeOrmModule.forRoot(typeORMConfig)
],
})
export class AppModule {}
3. board 모듈을 만들어 보도록 하겠습니다.
board 모듈 구조는 아래 그림과 같습니다.
board.entity.ts
- DB 테이블이 되는 Entity 객체
import { BaseEntity, Column, Entity, PrimaryGeneratedColumn } from "typeorm";
import { BoardStatus } from "./board-status.enum";
@Entity()
export class Board extends BaseEntity {
@PrimaryGeneratedColumn()
id:number;
@Column()
title:string;
@Column()
description:string;
@Column()
status:BoardStatus;
}
board.repository.ts
import { Repository } from "typeorm";
import { Board } from "./board.entity";
export class BoardRepository extends Repository<Board> {
}
boards.controller.ts
import { Body, Controller, Delete, Get, Param, ParseIntPipe, Patch, Post, UsePipes, ValidationPipe } from '@nestjs/common';
import { BoardsService } from './boards.service';
import { BoardStatus } from './board-status.enum';
import { CreateBoardDto } from './dto/create-board.dto';
import { Board } from './board.entity';
@Controller('boards')
export class BoardsController {
constructor( private boardsService : BoardsService) {}
// nest에서는 boardsService 인스턴스를 프로퍼티라고 부르는 것 같다
@Get('/:id')
getBoardById(@Param('id') id:number) : Promise<Board> {
return this.boardsService.getBoardById(id);
}
@Post()
@UsePipes(ValidationPipe)
createBoard(@Body() createBoardDto: CreateBoardDto) : Promise<Board> {
return this.boardsService.createBoard(createBoardDto);
}
@Patch('/:id/status')
updateBoardStatus(
@Param('id', ParseIntPipe) id: number,
@Body('status') status : BoardStatus
) {
return this.boardsService.updateBoardStatus(id, status);
}
@Delete('/:id')
deleteBoard(@Param('id', ParseIntPipe) id: number) {
return this.boardsService.deleteBoard(id);
}
}
- validationPipe를 사용하기 위해서는 아래와 같이 npm install이 필요합니다.
설치하게되면 기본적인 validation 체크를 위한 데코레이터를 사용할 수 있습니다.
npm install class-validator class-transformer --save
boards.service.ts
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { BoardStatus } from './board-status.enum';
import { Board } from './board.entity';
import { CreateBoardDto } from './dto/create-board.dto';
@Injectable() // nest js 어디에서나 사용할 수 있게 해준다
export class BoardsService {
constructor(
@InjectRepository(Board)
private boardRepository : Repository<Board>,
){}
async getBoardById(id: number): Promise <Board> {
const found = await this.boardRepository.findOneBy({id});
if(!found) {
throw new NotFoundException(`Can't find Board with id ${id}`);
}
return found;
}
async createBoard(createBoardDto : CreateBoardDto) : Promise<Board> {
const {title, description} = createBoardDto;
const board = this.boardRepository.create({
title,
description,
status: BoardStatus.PUBLIC
})
await this.boardRepository.save(board);
return board;
}
async updateBoardStatus(id:number, status: BoardStatus) : Promise<Board> {
const board = await this.getBoardById(id);
board.status = status;
await this.boardRepository.save(board);
return board;
}
async deleteBoard(id:number) : Promise<void> {
const result = await this.boardRepository.delete(id);
if(result.affected === 0 ) {
throw new NotFoundException(`Can't find Board with id ${id}`);
}
}
}
create-board.dto.ts
- dto class
import { IsNotEmpty } from "class-validator";
export class CreateBoardDto{
@IsNotEmpty()
title:string;
@IsNotEmpty()
description:string;
}
board-status.enum.ts
- BoardStatus를 상수로 쓰기 위한 enum
// 게시판 모델 정의
// interface : 변수의 타입만의 체크한다.
// classes : 변수의 타입도 체크하고 인스턴스 생성할 수 있다.
// export interface Board {
// id: string;
// title: string;
// description: string;
// status: BoardStatus
// }
export enum BoardStatus {
PUBLIC = 'PUBLIC',
PRIVATE = 'PRIVATE'
}
boards.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Board } from './board.entity';
import { BoardsController } from './boards.controller';
import { BoardsService } from './boards.service';
@Module({
imports: [
TypeOrmModule.forFeature([Board])
],
controllers: [BoardsController],
providers: [BoardsService]
})
export class BoardsModule {}
app.module.ts
- imports에 BoardsModule을 추가합니다.
import { Module } from '@nestjs/common';
import { BoardsModule } from './boards/boards.module';
import { TypeOrmModule } from '@nestjs/typeorm';
import { typeORMConfig } from './configs/config.typeorm';
@Module({
imports: [
TypeOrmModule.forRoot(typeORMConfig),
BoardsModule
],
})
export class AppModule {}
참조
728x90
반응형
'NestJS' 카테고리의 다른 글
[Nest.js] PIPE (0) | 2023.08.27 |
---|---|
[Nest.js] 기본 파일 구조 및 요청 흐름 (2) | 2023.08.20 |
[Nest.js] Quick Start! (0) | 2023.08.15 |