NestJS -2

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

nestJS-study

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

์‹œ์ž‘ ์ „ PC ๊ฐ€ ๋ฐ”๋€Œ์–ด ์ƒˆ๋กœ์šด PC์— ํ”„๋กœ์ ํŠธ๋ฅผ ์„ค์ •ํ•ด์•ผ ํ–ˆ๋‹ค.
git์— nestjs-board-app์„ ์—…๋กœ๋“œ ํ•ด๋†“์•„์„œ gitclone ์œผ๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ ์—ด๊ณ 
cmd ์— 'nest i -g @nest/cli' ์‹คํ–‰ ํ›„ ํ”„๋กœ์ ํŠธ๋ฅผ ์—ด์–ด๋ณด๋‹ˆ main.ts ์— ์˜ค๋ฅ˜๊ฐ€ ๋–  ์žˆ์—ˆ๋‹ค..

Cannot find module '@nestjs/core' or its corresponding type declarations.

๋ผ๋Š” ์˜ค๋ฅ˜์˜€๊ณ , ์‰ฝ๊ฒŒ ํ•ด๊ฒฐ ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.
terminal ์— 'npm install @nestjs/core'์™€ 'npm install @nestjs/common' ์„ ์ž…๋ ฅํ•˜์—ฌ ํ•ด๊ฒฐํ•˜์˜€๋‹ค.

๋ชจ๋“  ๊ฒŒ์‹œ๋ฌผ์„ ๊ฐ€์ ธ์˜ค๋Š” ์„œ๋น„์Šค ๋งŒ๋“ค๊ธฐ (CRUD => R)

๋ชจ๋“  ๊ฒŒ์‹œ๋ฌผ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๊ฐ€์ ธ์˜ค๋Š” ๋กœ์ง ๊ตฌํ˜„

๋กœ์ง์€ Service์—์„œ ๊ตฌํ˜„. ๋ฐ”๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์—ฐ๋™ํ•ด์„œ ํ•˜๋ฉด ๋˜์ง€๋งŒ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐํ•ด์„œ ํ•˜๋ฉด ํ—ท๊ฐˆ๋ฆด์ˆ˜์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์šฐ์„  ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ์ปฌ ๋ฉ”๋ชจ๋ฆฌ์— ๋‹ด์•„์„œ ์ฒ˜๋ฆฌ
<board.service.ts>

 import { Injectable } from '@nestjs/common';

@Injectable()
export class BoardsService {
    private boards =[];

    getAllBoards(){
        return this.boards;
    }
}

private boards์˜ private ์‚ฌ์šฉ ์ด์œ  : ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ด BoardsService์— ์ ‘๊ทผํ•ด์„œ ์ด boards ๋ฐฐ์—ด ๊ฐ’์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ

<board.controller.ts>

import { Controller, Get } from '@nestjs/common';
import { BoardsService } from './boards.service';

@Controller('boards')
export class BoardsController {
    constructor(private boardService: BoardsService) {}

    @Get()
    getAllBoard() {
        return this.boardService.getAllBoards;
    }
}

'npm run start:dev' ๋กœ ์‹คํ–‰, localhost:3000/boards ํ™•์ธ

=> ํด๋ผ์ด์–ธํŠธ์—์„œ ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด ๋จผ์ € ์ปจํŠธ๋กค๋Ÿฌ๋กœ ๊ฐ€๋ฉฐ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์•Œ๋งž์€ ์š”์ฒญ ๊ฒฝ๋กœ์—
๋ผ์šฐํŒ…ํ•ด์„œ ํ•ด๋‹น ํ•ธ๋“ค๋Ÿฌ๋กœ ๊ฐ€๊ฒŒ ํ•œ๋‹ค. ๊ทธ๋Ÿฐ ํ›„์— ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•ด์ฃผ๊ธฐ ์œ„ํ•ด์„œ ์„œ๋น„์Šค๋กœ ๋“ค์–ด๊ฐ€๋ฉฐ ๊ทธ ์š”์ฒญ์— ๋งž๋Š” ๋กœ์ง์„ ์„œ๋น„์Šค์—์„œ ์ฒ˜๋ฆฌํ•ด์ค€ ํ›„ ์ปจํŠธ๋กค๋Ÿฌ์— ๋ฆฌํ„ด๊ฐ’์„ ๋ณด๋‚ด์ค€ํ›„ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ํด๋ผ์ด์–ธํŠธ๋กœ ๊ฒฐ๊ณผ๊ฐ’์„ ๋ณด๋‚ด์ค€๋‹ค.
์ปจํŠธ๋กค๋Ÿฌ์—์„œ๋Š” ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ๊ฒฐ๊ณผ๊ฐ’์„ ๋ฆฌํ„ดํ•ด์ฃผ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.

Board Model ์ •์˜ํ•˜๊ธฐ

๊ฒŒ์‹œ๋ฌผ ๋ฐ์ดํ„ฐ์—๋Š” ID๊ฐ€ ํ•„์š”ํ•˜๊ณ  ์ด๋ฆ„์ด๋‚˜ ์„ค๋ช…๋“ฑ์ด ํ•„์š” ํ•˜๋‹ค๋Š” ์ •์˜๋ฅผ ํ† ๋Œ€๋กœ ์‹œ์ž‘!

๋ชจ๋ธ์„ ์ •์˜ํ•˜๊ธฐ ์œ„ํ•ด์„œ

Class๋ฅผ ์ด์šฉํ•˜๊ฑฐ๋‚˜ Interface ์ด์šฉ

  • Interface : ๋ณ€์ˆ˜์˜ ํƒ€์ž…๋งŒ ์ฒดํฌ
  • Classes : ๋ณ€์ˆ˜์˜ ํƒ€์ž…, ์ธ์Šคํ„ด์Šค ๋˜ํ•œ ์ƒ์„ฑ ๊ฐ€๋Šฅ

์šฐ์„  Interface ์‚ฌ์šฉ

  • status : ๊ฒŒ์‹œ๊ธ€์ด ๊ณต๊ฐœ์ธ์ง€ ๋น„๊ณต๊ฐœ์ธ์ง€ ๋‚˜๋ˆ ์ฃผ๋Š” ๊ฒƒ
    ๋‘๊ฐ€์ง€ ์ƒํƒœ ์ด์™ธ์˜ ๊ฒƒ์€ ๋‚˜์˜ค๋ฉด ์•ˆ๋˜๊ธฐ ๋•Œ๋ฌธ์— ํƒ€์ž…์Šคํฌ๋ฆฝ์Šค์˜ ๊ธฐ๋Šฅ์ธ enumeration์„ ์‚ฌ์šฉ

<board.model.ts>

export interface Board{
    id : string,
    title : string,
    dedcription: string,
    status: BoardStatus; //PUBLIC or PRIVATE
}

export enum BoardStatus {
    PUBLIC = 'PUBLIC',
    PRIVATE ='PRIVATE' 
}

์ƒ์„ฑํ•œ Board ๋ชจ๋ธ์„ ์ด์šฉํ•ด์„œ ํƒ€์ž…์„ ์ •์˜ โฌ‡
<boards.service.ts>

import { Injectable } from '@nestjs/common';
import { Board } from './board.model';

@Injectable()
export class BoardsService {
    private boards: Board[] = []; // ๋ฐฐ์—ด์ฃผ์˜

    getAllBoards(): Board[] { //๋ฐฐ์—ด์ฃผ์˜
        return this.boards;
    }
}

<boards.controller.ts>

import { Controller, Get } from '@nestjs/common';
import { BoardsService } from './boards.service';
import { Board } from './board.model';

@Controller('boards')
export class BoardsController {
    constructor(private boardsService: BoardsService) {}

    @Get('/')
    getAllBoard(): Board[] { //๋ฐฐ์—ด์ฃผ์˜
        return this.boardsService.getAllBoards();
    }
}

ํƒ€์ž…์„ ์ •์˜ํ•˜๋ฉด ์ข‹์€ ์ด์œ 

  1. ํƒ€์ž…์„ ์ •์˜ํ•ด์ฃผ๋ฏ€๋กœ์„œ ์›ํ•˜๋Š” ํƒ€์ž…๊ณผ ๋‹ค๋ฅธ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์‹œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒ
  2. ์ฝ”๋“œ๋ฅผ ์ฝ๋Š” ์ž…์žฅ์—์„œ ๋” ์ฝ”๋“œ๋ฅผ ์‰ฝ๊ฒŒ ์ดํ•ดํ•˜๋ฉฐ ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค. (readable)

๊ฒŒ์‹œ๋ฌผ ์ƒ์„ฑํ•˜๊ธฐ (CRUD => C) : Service

๊ฒŒ์‹œ๋ฌผ ์ƒ์„ฑ ๊ธฐ๋Šฅ ๋งŒ๋“ค๊ธฐ

๊ฒŒ์‹œ๋ฌผ์— ๊ด€ํ•œ ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ถ€๋ถ„์€ Service , Service ์—์„œ ์ฒ˜๋ฆฌ ํ›„ Controller์—์„œ ์„œ๋น„์Šค๋ฅผ ํ˜ธ์ถœ

id ๋Š” ๋ชจ๋“  ๊ฒŒ์‹œ๋ฌผ์— ์œ ๋‹ˆํฌ ํ•ด์•ผํ•œ๋‹ค. ๋งŒ์•ฝ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์–ด์ฃผ๋Š” ๊ฒฝ์šฐ๋ผ๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์•Œ์•„์„œ ์œ ๋‹ˆํฌํ•œ ๊ฐ’์„ ์ฃผ์ง€๋งŒ ์ง€๊ธˆ์€ ์ž„์˜๋กœ ๊ฐ’์„ ์ฃผ์–ด์•ผํ•จ
=> uuid ๋ชจ๋“ˆ์„ ์ด์šฉ

uuid ๋ชจ๋“ˆ

npm install uuid --save

service ์— 'import { v1 as uuid } from 'uuid';' ์ถ”๊ฐ€

<boards.service.ts>

import { Injectable } from '@nestjs/common';
import { Board, BoardStatus } from './board.model';
import { v1 as uuid } from 'uuid';

@Injectable()
export class BoardsService {
    private boards: Board[] = [];

    getAllBoards(): Board[] {
        return this.boards;
    }

    createBoard(title: string, description: string){
        const board: Board={
            id: uuid(),
            //title: title -> ๊ทธ๋ƒฅ title๋กœ ์ƒ๋žต๊ฐ€๋Šฅ : ์•ž๋’ค ๋ณ€์ˆ˜๋ช…์ด ๋™์ผ
            title,
            // description: description
            description,
            status: BoardStatus.PUBLIC
        }

        //๊ฒŒ์‹œํŒ์— ๊ฒŒ์‹œ๊ธ€ ์ƒ์„ฑํ•œ ๊ฒƒ์„ ๋„ฃ์–ด์ฃผ๊ธฐ
        this.boards.push(board);
        return board;
    }
}

๊ฒŒ์‹œ๋ฌผ ์ƒ์„ฑํ•˜๊ธฐ (CRUD => C) : Controller

Request, Response

controller ์— ์ •์˜

ํด๋ผ์ด์–ธํŠธ์—์„œ ๋ณด๋‚ด์˜จ ๊ฐ’์„ ํ•ธ๋“ค๋Ÿฌ์— ๊ฐ€์ ธ์˜ค๊ธฐ

ํด๋ผ์ด์–ธํŠธ์—์„œ์˜ ์ •๋ณด ๋ฐ›์•„์˜ค๊ธฐ
=> @Body body ..
<boards.controller.ts>

import { Body, Controller, Get, Post } from '@nestjs/common';
import { BoardsService } from './boards.service';
import { Board } from './board.model';

@Controller('boards')
export class BoardsController {
    constructor(private boardsService: BoardsService) {}

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

    //body ์ „์ฒด ํ•œ๋ฒˆ์— ๊ฐ€์ ธ์˜ค๊ธฐ
    // @Post()
    // createBoard(@Body() body) {
    //     console.log('body', body);
    // }

    //body ์˜ ํŠน์ • ๊ฐ’๋งŒ ๊ฐ€์ ธ์˜ค๊ธฐ
    // @Post()
    // createBoard(@Body('title') title: string, @Body('description') description: string) {
    //     console.log('title', title);
    //     console.log('description', description);
    // }

    @Post()
    createBoard(@Body('title') title: string, @Body('description') description: string): Board { //return ๊ฐ’์˜ ํƒ€์ž…์€ Board, Board[]๋กœ ์ฃผ๋ฉด ์•ˆ๋จ : service์˜ createBoard์˜ return ๊ฐ’์ด board ํ•˜๋‚˜์ด๊ธฐ ๋•Œ๋ฌธ์—
        return this.boardsService.createBoard(title, description);
    }

}

์œ„์˜ ์ฃผ์„ ์ค‘์š”!!

POSTMAN ์œผ๋กœ ํ…Œ์ŠคํŠธ

Data transfer Object(DTO)

DTO (Data Transfer Object)

  • ๊ณ„์ธต๊ฐ„ ๋ฐ์ดํ„ฐ ๊ตํ™˜์„ ์œ„ํ•œ ๊ฐ์ฒด
  • DB์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์–ป์–ด Service๋‚˜ Controller ๋“ฑ์œผ๋กœ ๋ณด๋‚ผ ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ์ฒด
  • DTO๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ๋„คํŠธ์›Œํฌ๋ฅผ ํ†ตํ•ด ์ „์†ก๋˜๋Š” ๋ฐฉ๋ฒ•์„ ์ •์˜ํ•˜๋Š” ๊ฐ์ฒด
  • interface๋‚˜ class๋ฅผ ์ด์šฉํ•ด์„œ ์ •์˜ ๋  ์ˆ˜ ์žˆ๋‹ค. (ํ•˜์ง€๋งŒ ํด๋ž˜์Šค๋ฅผ ์ด์šฉํ•˜๋Š”๊ฒƒ์„ Nest JS์—์„œ๋Š” ์ถ”์ฒœ)

DTO๋ฅผ ์“ฐ๋Š” ์ด์œ 

  • ๋ฐ์ดํ„ฐ ์œ ํšจ์„ฑ์„ ์ฒดํฌํ•˜๋Š”๋ฐ ํšจ์œจ์ 
  • ๋” ์•ˆ์ •์ ์ธ ์ฝ”๋“œ๋กœ ๋งŒ๋“ค์–ด ์ค€๋‹ค.
  • ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์˜ ํƒ€์ž…์œผ๋กœ๋„ ์‚ฌ์šฉ๋œ๋‹ค.

ํ”„๋กœํผํ‹ฐ(title, description...)๊ฐ€ ๋งŽ์„ ๋•Œ ํ”„๋กœํผํ‹ฐ์˜ ์ด๋ฆ„์„ ๋ฐ”๊ฟ”์•ผํ•œ๋‹ค๋ฉด controller, service ๋“ฑ ์—ฌ๋Ÿฌ ๊ณณ์—์„œ ๋ฐ”๊ฟ”์ค˜์•ผํ•œ๋‹ค.
=> ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ํž˜๋“ฆ => DTO ์‚ฌ์šฉ

๊ฒŒ์‹œ๋ฌผ ์ƒ์„ฑ์„ ์œ„ํ•œ DTO

DTO ํŒŒ์ผ ์ž‘์„ฑ

ํด๋ž˜์Šค๋Š” ์ธํ„ฐํŽ˜์ด์Šค์™€ ๋‹ค๋ฅด๊ฒŒ ๋Ÿฐํƒ€์ž„์—์„œ ์ž‘๋™ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํŒŒ์ดํ”„ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ์ด์šฉํ•  ๋•Œ ๋” ์œ ์šฉํ•˜๋‹ค.
=> ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•ด์„œ DTO๋ฅผ ์ž‘์„ฑ
<create-board.dto.ts>

export class createBoardDto{
    title: string;
    description: string;
}

DTO ์ ์šฉํ•˜๊ธฐ

<boards.controller.ts>

import { Body, Controller, Get, Post } from '@nestjs/common';
import { BoardsService } from './boards.service';
import { Board } from './board.model';
import { createBoardDto } from './dto/create-board.dto';

@Controller('boards')
export class BoardsController {
    constructor(private boardsService: BoardsService) {}

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

    //body ์ „์ฒด ํ•œ๋ฒˆ์— ๊ฐ€์ ธ์˜ค๊ธฐ
    // @Post()
    // createBoard(@Body() body) {
    //     console.log('body', body);
    // }

    //body ์˜ ํŠน์ • ๊ฐ’๋งŒ ๊ฐ€์ ธ์˜ค๊ธฐ
    // @Post()
    // createBoard(@Body('title') title: string, @Body('description') description: string) {
    //     console.log('title', title);
    //     console.log('description', description);
    // }

    @Post()
    createBoard(
        @Body() createBoardDto: createBoardDto
    ): Board { //return ๊ฐ’์˜ ํƒ€์ž…์€ Board, Board[]๋กœ ์ฃผ๋ฉด ์•ˆ๋จ : service์˜ createBoard์˜ return ๊ฐ’์ด board ํ•˜๋‚˜์ด๊ธฐ ๋•Œ๋ฌธ์—
        return this.boardsService.createBoard(createBoardDto);
    }

}

<boards.service.ts>

import { Injectable } from '@nestjs/common';
import { Board, BoardStatus } from './board.model';
import { v1 as uuid } from 'uuid';
import { createBoardDto } from './dto/create-board.dto';

@Injectable()
export class BoardsService {
    private boards: Board[] = [];

    getAllBoards(): Board[] {
        return this.boards;
    }

    createBoard(createBoardDto: createBoardDto){
        // const title = createBoardDto.title;
        // const description = createBoardDto.description;
        const { title, description }= createBoardDto;
        const board: Board={
            id: uuid(),
            //title: title -> ๊ทธ๋ƒฅ title๋กœ ์ƒ๋žต๊ฐ€๋Šฅ : ์•ž๋’ค ๋ณ€์ˆ˜๋ช…์ด ๋™์ผ
            title,
            // description: description
            description,
            status: BoardStatus.PUBLIC
        }

        //๊ฒŒ์‹œํŒ์— ๊ฒŒ์‹œ๊ธ€ ์ƒ์„ฑํ•œ ๊ฒƒ์„ ๋„ฃ์–ด์ฃผ๊ธฐ
        this.boards.push(board);
        return board;
    }
}

ID๋กœ ํŠน์ • ๊ฒŒ์‹œ๋ฌผ ๊ฐ€์ ธ์˜ค๊ธฐ

service -> controller

<service.ts>

getBoardIs(id: string): Board{ //๊ฒŒ์‹œ๋ฌผ ํ•˜๋‚˜๋ฅผ return ํ•˜๊ธฐ ๋•Œ๋ฌธ์— Board[] X
        return this.boards.find((board)=>board.id === id);
    }

<controller.ts>

@Get('/:id')
    getBoardById(@Param('id') id: string): Board{
        return this.boardsService.getBoardId(id);
    }

Param

//ex) localhost:3000?id=11111 ์ผ ๋•Œ๋Š” 
findOne(@Param('id') id: string)
//ex) localhost:3000?id=11111&title=abcd ์ผ ๋•Œ๋Š” 
findOne(@Param() params: string[])

ID๋กœ ํŠน์ • ๊ฒŒ์‹œ๋ฌผ ์ง€์šฐ๊ธฐ

service -> controller

<service.ts>

deleteBoard(id: string): void{ // return ์„ ๋”ฐ๋กœ ์ฃผ์ง€ ์•Š์•„๋„ ๋˜๊ธฐ ๋•Œ๋ฌธ์— void
        this.boards = this.boards.filter((board) => board.id !==id);
    }

<controller.ts>

@Delete('/:id')
    deleteBoard(@Param('id') id: string): void {
        this.boardsService.deleteBoard(id);
    }

ํŠน์ • ๊ฒŒ์‹œ๋ฌผ์˜ ์ƒํƒœ ์—…๋ฐ์ดํŠธ

ํŠน์ • ๊ฒŒ์‹œ๋ฌผ์˜ ์ƒํƒœ(PUBLIC ๋˜๋Š” PRIVATE)์„ ์—…๋ฐ์ดํŠธ ํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ
<service.ts>

updateBoardStatus(id:string, status: BoardStatus):Board {
        const board = this.getBoardId(id);
        board.status = status;
        return board;
    }

<controller.ts>

@Patch('/:id/status')
    updateBoardStatus(
        @Param('id') id: string,
        @Body('status') status: BoardStatus
    ) {
        return this.boardsService.updateBoardStatus(id, status);
    }
profile
๊ฐœ๋ฐœ๊ฐ์ž
post-custom-banner

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

comment-user-thumbnail
2024๋…„ 4์›” 14์ผ

ํฌ

1๊ฐœ์˜ ๋‹ต๊ธ€