NestJS -4

sein leeยท2024๋…„ 4์›” 18์ผ
0

nestJS-study

๋ชฉ๋ก ๋ณด๊ธฐ
4/4
post-thumbnail
post-custom-banner

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ํ•จ๊ป˜ CRUD ๊ตฌํ˜„ ์œ„ํ•ด ์ •๋ฆฌํ•  ๋ถ€๋ถ„

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๋™์„ ์œ„ํ•ด CRUD ๊ตฌํ˜„์„ ์œ„ํ•ด ์ˆ˜์ • ํ•  ๋ถ€๋ถ„

1.๋จผ์ € Service ์™€ Controller ํŒŒ์ผ์—์„œ ๋กœ์ง๋“ค์„ ๋‹ค ์ˆ˜์ •ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์—
์›๋ž˜ ์žˆ๋˜ ๋ถ€๋ถ„๋“ค์„ ์ฃผ์„ ์ฒ˜๋ฆฌ ํ•œ๋‹ค.

  1. ๋ฉ”๋ชจ๋ฆฌ์— ๋ฐ์ดํ„ฐ ์ €์žฅ์ด ์•„๋‹ˆ๋‹ˆ Service์— board ๋ฐฐ์—ด์„ ์ง€์›Œ์ค๋‹ˆ๋‹ค.

  2. ๊ฒŒ์‹œ๋ฌผ ๋ฐ์ดํ„ฐ๋ฅผ ์ •์˜ํ•˜๋Š”๋ฐ Entity๋ฅผ ์ด์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— Board Model ํŒŒ์ผ์— ์žˆ๋Š” Board Interface๋Š” ์ง€์šฐ๊ณ 

  3. Status Enum ์€ ์•„์ง๋„ ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด ๋ถ€๋ถ„๋งŒ์„ ์œ„ํ•œ ํŒŒ์ผ์„ ์ƒ์„ฑํ•ด์„œ ๋„ฃ์–ด์ค๋‹ˆ๋‹ค.

  • board.model.ts ํŒŒ์ผ์„ board-status.enum.ts ์œผ๋กœ ๋ณ€๊ฒฝ
  1. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ด์šฉ์œผ๋กœ ์ธํ•œ ๋ถˆํ•„์š”ํ•œ ๊ฒฝ๋กœ ์ง€์›Œ์ฃผ๊ธฐ
  • board-status-validation.pipe.ts BoardStatus
  • boards.controller.ts
  • board.entity.ts BoardStatus
  • uuid

์•„์ด๋””๋ฅผ ์ด์šฉํ•ด์„œ ํŠน์ • ๊ฒŒ์‹œ๋ฌผ ๊ฐ€์ ธ์˜ค๊ธฐ

์ด์ œ๋Š” ๋ฉ”๋ชจ๋ฆฌ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š”๊ฒŒ ์•„๋‹Œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๊ฐ€์ ธ์˜ค๊ณ  TypeORM์„ ์“ธ ๋•Œ๋Š” Repository ํŒจํ„ด์„ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์—
Board ์„œ๋น„์Šค(service)์— Board ๋ฆฌํฌ์ง€ํ„ฐ๋ฆฌ(Repository)๋ฅผ ๋„ฃ์–ด์ค˜์•ผํ•œ๋‹ค.(์ข…์†์„ฑ์ฃผ์ž…, Inject)

Service์— Repository ๋„ฃ์–ด์ฃผ๊ธฐ (Repository Injection)

<board.service.ts>

constructor(
        @InjectRepository(BoardRepository)
        private boardRepository: BoardRepository,
        //private ์„ ์‚ฌ์šฉํ•˜๋ฉด ์•”๋ฌต์ ์œผ๋กœ boardRepository ์ธ์ž๊ฐ€ ํ”„๋กœํผํ‹ฐ๋กœ ์„ ์–ธ์ด ๋œ๋‹ค.
    ){}

@InjectRepository

  • ์ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์ด์šฉํ•ด์„œ ์ด ์„œ๋น„์Šค์—์„œ BoardRepository๋ฅผ ์ด์šฉํ•œ๋‹ค๊ณ  ํ•˜๊ณ  ์ด๊ฑธboardRepository ๋ณ€์ˆ˜์— ๋„ฃ์–ด์ค€๋‹ค.

Service์—์„œ getBoardById ๋ฉ”์†Œ๋“œ ์ƒ์„ฑํ•˜๊ธฐ

  • typeOrm ์—์„œ ์ œ๊ณตํ•˜๋Š” findOne ๋ฉ”์†Œ๋“œ ์‚ฌ์šฉ
  • async await์„ ์ด์šฉํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘์—…์ด ๋๋‚œ ํ›„ ๊ฒฐ๊ณผ๊ฐ’์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค

<service.ts>

async getBoardById(id: number): Promise <Board>{
        const found = await this.boardRepository.findOne({ where: { id } });

        if(!found){
            throw new NotFoundException(`Can't find Voard with id ${id}`)
        }
        return found;
    }

Controller ๋ถ€๋ถ„๋„ ์ˆ˜์ •ํ•˜๊ธฐ

<controller.ts>

@Get('/:id')
    getBoardById(@Param('id') id: number): Promise<Board>{
        return this.boardsService.getBoardById(id);
    }

<๊ฒฐ๊ณผ>

๊ฒŒ์‹œ๋ฌผ ์ƒ์„ฑํ•˜๊ธฐ

<board.service.ts>

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;
    }

<board.controller.ts>

 @Post()
    @UsePipes(ValidationPipe)
    createBoard(@Body() createBoardDto: createBoardDto): Promise<Board>{
        return this.boardsService.createBoard(createBoardDto);
    }


๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๊ด€๋ จ๋œ ๋กœ์ง์€ Repository๋กœ ์ด๋™...

Repository Pattern์€ ์„œ๋น„์Šค์— ์žˆ๋Š” ๋ฐ์ดํ…Œ๋ฒ ์ด์Šค๊ด€๋ จ ๋กœ์ง์„ Repository ์ชฝ์œผ๋กœ ์˜ฎ๊ธฐ๋ฉด ๋œ๋‹ค.

<board.repository.ts>

import { EntityRepository, Repository } from "typeorm";
import { Board } from "./board.entity";
import { createBoardDto } from "./dto/create-board.dto";
import { BoardStatus } from "./board-status.enum";

@EntityRepository(Board)
export class BoardRepository extends Repository<Board>{
    async createBoard(createBoardDto: createBoardDto) : Promise<Board> {
        const {title, description} = createBoardDto;

        const board = this.create({
            title,
            description,
            status: BoardStatus.PUBLIC
        })
   
        await this.save(board);
        return board;
    }
    
}

<board.service.ts>

//๊ฒŒ์‹œ๋ฌผ์ƒ์„ฑํ•˜๊ธฐ2
    createBoard(createBoardDto: createBoardDto): Promise<Board> {
        return this.boardRepository.createBoard(createBoardDto);
    }

<๊ฒฐ๊ณผ>
???

๊ฒŒ์‹œ๋ฌผ ์‚ญ์ œํ•˜๊ธฐ

remove() vs delete()

  • remove ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์‚ญ์ œ๋Œ€์ƒ ์•„์ดํ…œ์ด ๋ฌด์กฐ๊ฑด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์•ˆ์— ์žˆ์–ด์•ผํ•œ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์—๋Ÿฌ(404)

  • delete: ์•„์ดํ…œ์ด ์กด์žฌํ•˜๋ฉด ์ง€์šฐ๊ณ  ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด ์•„๋ฌด๋Ÿฐ ์˜ํ–ฅ์ด ์—†๋‹ค.

์ด๋Ÿฌํ•œ ์ฐจ์ด ๋•Œ๋ฌธ์— remove๋ฅผ ์ด์šฉํ•˜๋ฉด ํ•˜๋‚˜์˜ ์•„์ดํ…œ์„ ์ง€์šธ ๋•Œ ๋‘๋ฒˆ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์ด์šฉํ•ด์•ผํ•œ๋‹ค.(์•„์ดํ…œ ์œ ๋ฌด + ์ง€์šฐ๊ธฐ) ๋”ฐ๋ผ์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ํ•œ๋ฒˆ๋งŒ ์ ‘๊ทผํ•ด๋„ ๋˜๋Š” delete ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์ค€๋‹ค.

<board.service.ts>

async deleteBoard(id: number): Promise<void> {
        const result = await this.boardRepository.delete(id);

        console.log('result', result);
    }

<board.controller.ts>

@Delete('/:id')
    deleteBoard(@Param('id', ParseIntPipe) id: number): Promise<void> {
        return this.boardsService.deleteBoard(id);
    }
  • ParseIntPipe

delete๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์—†๋Š” id ๋ฅผ ์ง€์šฐ๋”๋ผ๊ณ  ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.
=> ๋”ฐ๋กœ ์—๋Ÿฌ๋ฉ”์„ธ์ง€๋ฅผ ์ถœ๋ ฅํ•ด๋ณด์ž.
<serviec.ts>

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}`)
        }
        console.log('result', result);
    }
    ```
![](https://velog.velcdn.com/images/baby_potato/post/df1f4c4a-0fe1-4ec1-bd70-998325b6e808/image.png)
    
# ๊ฒŒ์‹œ๋ฌผ ์ƒํƒœ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ

<board.service.ts>
```ts
async updateBoardStatus(id: number, status: BoardStatus): Promise<Board> {
        const board = await this.getBoardById(id);
        board.status = status;

        await this.boardRepository.save(board);

        return board;
    }

<board.controller.ts>

 @Patch('/:id/status')
    updateBoardStatus(
        @Param( 'id', ParseIntPipe) id: number,
        @Body('status', BoardStatusValidationPipe) status: BoardStatus,
    ): Promise<Board> {
        return this,this.boardsService.updateBoardStatus(id,status);
    }
    ```
    
 ![](https://velog.velcdn.com/images/baby_potato/post/30c8be7d-6349-4f2c-8477-bf12bd519f83/image.png)

# ๋ชจ๋“  ๊ฒŒ์‹œ๋ฌผ ๊ฐ€์ ธ์˜ค๊ธฐ
<board.service.ts>
```ts
async getAllBoards(): Promise<Board[]> {
        return this.boardRepository.find();
    }

<board.controller.ts>

@Get('/')
    getAllBoard(): Promise<Board[]> {
        return this.boardsService.getAllBoards();
    }

profile
๊ฐœ๋ฐœ๊ฐ์ž
post-custom-banner

0๊ฐœ์˜ ๋Œ“๊ธ€