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
복사
Related Posts
Search