Blog

[NestJS] 6. DB+TypeORM → CRUD Operation 연동 리팩토링 | 🎯 중요

Category
Author
citeFred
citeFred
PinOnMain
1 more property
NestJS, TypeORM 이해하기
Table of Content

1. Service 계층 리팩토링

임시DB에서 MySQL, TypeORM을 적용했으므로 Service 계층 코드를 전체적으로 수정한다.
임시 비활성화 주석 부분을 모두 삭제해도 무방하다 전반적인 코드가 async/await 문법으로 수정되었다.
CREATE, UPDATE 기능은 save() 메서드를 사용했다.
create() 메서드는 저장 전 DTO객체를 Entity 클래스를 참조한 인스턴스를 생성한다.
PATCH 메서드의 일부 수정 기능은 update() 메서드를 사용했다.
READ 중 전체 조회 기능은 find() 메서드를 사용했다.
READ 중 특정 조회 기능은 findOneBy(), findBy() 메서드 사용했다.
findOneOrFail() 처럼 예외 처리를 함께 할 수 있는 메서드도 존재
DELETE 기능은 remove(), delete() 메서드를 사용할 수 있다.
Cascade 에 대해 인지하고 사용해야 한다.
boards.service.ts
import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common'; import { Board } from './boards.entity'; import { BoardStatus } from './boards-status.enum'; import { CreateBoardDto } from './dto/create-board.dto'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { UpdateBoardDto } from './dto/update-board.dto'; @Injectable() export class BoardsService { // Repository 계층 DI constructor( @InjectRepository(Board) private boardRepository : Repository<Board> ){} // 게시글 조회 기능 async getAllBoards(): Promise<Board[]> { const foundBoards = await this.boardRepository.find(); return foundBoards; } // 특정 게시글 조회 기능 async getBoardDetailById(id: number): Promise<Board> { const foundBoard = await this.boardRepository.findOneBy({ id: id }); if(!foundBoard) { throw new NotFoundException(`Board with ID ${id} not found`); } return foundBoard; } // 키워드(작성자)로 검색한 게시글 조회 기능 async getBoardsByKeyword(author: string): Promise<Board[]> { if (!author) { throw new BadRequestException('Author keyword must be provided'); } const foundBoards = await this.boardRepository.findBy({ author: author }) if (foundBoards.length === 0) { throw new NotFoundException(`No boards found for author: ${author}`); } return foundBoards; } // 게시글 작성 기능 async createBoard(createBoardDto: CreateBoardDto): Promise<Board> { const { author, title, contents } = createBoardDto; if (!author || !title || !contents) { throw new BadRequestException('Author, title, and contents must be provided'); } const newBoard: Board = { id: 0, // 임시 초기화 author, // author: createBoardDto.author title, contents, status: BoardStatus.PUBLIC }; const createdBoard = await this.boardRepository.save(newBoard); return createdBoard; } // 특정 번호의 게시글 수정 async updateBoardById(id: number, updateBoardDto: UpdateBoardDto): Promise<Board> { const foundBoard = await this.getBoardDetailById(id); const { title, contents } = updateBoardDto; if (!title || !contents) { throw new BadRequestException('Title and contents must be provided'); } foundBoard.title = title; foundBoard.contents = contents; const updatedBoard = await this.boardRepository.save(foundBoard) return updatedBoard; } // 특정 번호의 게시글 일부 수정 async updateBoardStatusById(id: number, status: BoardStatus): Promise<void> { const result = await this.boardRepository.update(id, { status }); if (result.affected === 0) { throw new NotFoundException(`Board with ID ${id} not found`); } } // 게시글 삭제 기능 async deleteBoardById(id: number): Promise<void> { const foundBoard = await this.getBoardDetailById(id); await this.boardRepository.delete(foundBoard); } }
TypeScript
복사

2. Controller 계층 리팩토링

Service 계층 수정사항에 따라 일부 반환 타입등에 Promise가 추가되었으므로 아래처럼 Controller도 수정한다.
임시 주석을 해제하고 일부 변경 사항을 확인하여 수정한다.
단일 객체 반환은 Promise<Board> 리스트 배열 반환은 Promise<Board[]> 와 같다.
boards.controller.ts
import { Body, Controller, Delete, Get, Param, Patch, Post, Put, Query, UsePipes, ValidationPipe } from '@nestjs/common'; import { BoardsService } from './boards.service'; import { Board } from './boards.entity'; import { CreateBoardDto } from './dto/create-board.dto'; import { BoardResponseDto } from './dto/board-response.dto'; import { BoardSearchResponseDto } from './dto/board-search-response.dto'; import { UpdateBoardDto } from './dto/update-board.dto'; import { BoardStatusValidationPipe } from './pipes/board-status-validation.pipe'; import { BoardStatus } from './boards-status.enum'; @Controller('api/boards') @UsePipes(ValidationPipe) export class BoardsController { // 생성자 주입 constructor(private boardsService: BoardsService){} // 게시글 조회 기능 @Get('/') async getAllBoards(): Promise<BoardResponseDto[]> { const boards: Board[] = await this.boardsService.getAllBoards(); const boardsResponseDto = boards.map(board => new BoardResponseDto(board)); return boardsResponseDto; } // 특정 게시글 조회 기능 @Get('/:id') async getBoardDetailById(@Param('id') id: number): Promise<BoardResponseDto> { const boardResponseDto = new BoardResponseDto(await this.boardsService.getBoardDetailById(id)); return boardResponseDto; } // 키워드(작성자)로 검색한 게시글 조회 기능 @Get('/search/:keyword') async getBoardsByKeyword(@Query('author') author: string): Promise<BoardSearchResponseDto[]> { const boards: Board[] = await this.boardsService.getBoardsByKeyword(author); const boardsResponseDto = boards.map(board => new BoardSearchResponseDto(board)); return boardsResponseDto; } // 게시글 작성 기능 @Post('/') async createBoard(@Body() createBoardDto: CreateBoardDto): Promise<BoardResponseDto> { const boardResponseDto = new BoardResponseDto(await this.boardsService.createBoard(createBoardDto)) return boardResponseDto; } // 특정 번호의 게시글 수정 @Put('/:id') async updateBoardById( @Param('id') id: number, @Body() updateBoardDto: UpdateBoardDto): Promise<BoardResponseDto> { const boardResponseDto = new BoardResponseDto(await this.boardsService.updateBoardById(id, updateBoardDto)) return boardResponseDto; } // 특정 번호의 게시글 일부 수정 @Patch('/:id') async updateBoardStatusById( @Param('id') id: number, @Body('status', BoardStatusValidationPipe) status: BoardStatus): Promise<void> { await this.boardsService.updateBoardStatusById(id, status); } // 게시글 삭제 기능 @Delete('/:id') async deleteBoardById(@Param('id') id: number): Promise<void> { await this.boardsService.deleteBoardById(id); } }
TypeScript
복사
Search
 | Main Page | Category |  Tags | About Me | Contact | Portfolio