Nest.js 입문
게시판 만들어보기 Part.1
board 모듈, 컨트롤러,서비스 생성
// 모듈
nest g mo board
// 컨트롤러
nest g co board
// 서비스
nest g s board
import { Controller } from '@nestjs/common';
@Controller('board')
export class BoardController {}컨트롤러 데코레이터 옆에 문자열은 라우팅이다.!!!
이 컨트롤러는 /board 라는 주소 아래로 요청을 하면 해당 컨트롤러에서 처리
게시판 만들어보기 Part.2
lodash - Javascript로 코딩할 때 유용하게 사용할 수 있는 유틸성 패키지
lodash 패키지 설치
npm i lodash
ES6 모듈 사양을 준수하여 CommonJS 모듈을 가져올 수 있게
tsconfig.json 수정
"esModuleInterop": true
board.controller.ts
import { Controller, Delete, Get, Post, Put } from '@nestjs/common';
import { BoardService } from './board.service';
@Controller('board')
export class BoardController {
  // 서비스 주입
  constructor(private readonly boardService: BoardService) {}
  //전체 게시글 가져오기
  @Get('/articles')
  getArticles() {
    return this.boardService.getArticles();
  }
  //게시글 상세보기
  @Get('/articles/:id')
  getArticleById() {
    return this.boardService.getArticleById(id);
  }
  // 게시글 작성
  @Post('/articles')
  createArticle() {
    return this.boardService.createArticle();
  }
  // 게시글 수정
  @Put('/articles/:id')
  updateArticle() {
    return this.boardService.updateArticle(id);
  }
  // 게시글 삭제
  @Delete('/articles/:id')
  deleteArticle() {
    return this.boardService.deleteArticle(id);
  }
}POST, PUT의 경우에는 클라이언트로부터 데이터를 전달받아야 생성하거나 수정합니다.
Express에서는 req.body에 담긴 데이터를 받았는데 Nest.js에서는 어떻게 받아올까??
Nest.js에서는 클라이언트로부터 데이터를 받거나 데이터를 줘야 할 때는 DTO를 사용해야 합니다.
DTO (Data Transfer Object)는 클라이언트와 서버 간의 데이터 전송에 사용되는 객체
DTO는 서버로 전송되는 데이터를 표현하는 객체로,
데이터를 송신하는 클라이언트와 수신하는 서버 사이에서 인터페이스의 역할
class-validator 패키지로 입력값 유효성 검사
npm i class-validator
create-article.dto.ts
import { IsNumber, IsString } from 'class-validator';
export class CreateArticleDto {
  @IsString()
  readonly title: string;
  @IsString()
  readonly content: string;
  @IsNumber()
  readonly password: number;
}
update-article.dto.ts
import { IsNumber, IsString } from 'class-validator';
export class UpdateArticleDto {
  @IsString()
  readonly title: string;
  @IsString()
  readonly content: string;
  @IsNumber()
  readonly password: number;
}
delete-article.dto.ts
import { IsNumber } from 'class-validator';
export class DeleteArticleDto {
  @IsNumber()
  readonly password: number;
}
@IsString(), @IsNumber() 는 class-validator에서 제공하는 데코레이터이다.
각 dto.ts 코드를 보면 비슷하다
@nestjs/mapped-types 패키지를 사용해서 PartialType, PickType 등을 사용하면 코드를 깔끔하게 줄일수있다.
@nestjs/mapped-types 패키지 설치
npm i @nestjs/mapped-types
설치 중 오류가 난다면(의존성 이슈)
해당하는 패키지를 삭제 하고 제일 나중에 설치 하자
npm uninstall class-validator
npm i @nestjs/mapped-types
npm i class-validator
@nestjs/mapped-types 패키지를 사용해서 아래와 같이 코드를 줄일수있다.
update-article.dto.ts
import { PartialType } from '@nestjs/mapped-types';
import { CreateArticleDto } from './create-article.dto';
export class UpdateArticleDto extends PartialType(CreateArticleDto) {}
delete-article.dto.ts
import { PickType } from '@nestjs/mapped-types';
import { CreateArticleDto } from './create-article.dto';
export class DeleteArticleDto extends PickType(CreateArticleDto, [
  'password',
] as const) {}
DTO의 유효성 검사를 하기 위해서 main.ts 수정
import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(new ValidationPipe());
  await app.listen(3000);
}
bootstrap();
유효성 검사 데코레이터는 DTO에서 한 번만 정의하면 된다.
board.controller.ts
import {
  Body,
  Controller,
  Delete,
  Get,
  Param,
  Post,
  Put,
} from '@nestjs/common';
import { BoardService } from './board.service';
import { CreateArticleDto } from './create-article.dto';
import { DeleteArticleDto } from './delete-article.dto';
import { UpdateArticleDto } from './update-article.dto';
@Controller('board')
export class BoardController {
  // 서비스 주입
  constructor(private readonly boardService: BoardService) {}
  //전체 게시글 가져오기
  @Get('/articles')
  getArticles() {
    return this.boardService.getArticles();
  }
  //게시글 상세보기
  @Get('/articles/:id')
  getArticleById(@Param('id') articleId: number) {
    return this.boardService.getArticleById(articleId);
  }
  // 게시글 작성
  @Post('/articles')
  createArticle(@Body() data: CreateArticleDto) {
    return this.boardService.createArticle(
      data.title,
      data.content,
      data.password,
    );
  }
  // 게시글 수정
  @Put('/articles/:id')
  updateArticle(
    @Param('id') articleId: number,
    @Body() data: UpdateArticleDto,
  ) {
    return this.boardService.updateArticle(
      articleId,
      data.title,
      data.content,
      data.password,
    );
  }
  // 게시글 삭제
  @Delete('/articles/:id')
  deleteArticle(
    @Param('id') articleId: number,
    @Body() data: DeleteArticleDto,
  ) {
    return this.boardService.deleteArticle(articleId, data.password);
  }
}
board.service.ts
import {
  Injectable,
  NotFoundException,
  UnauthorizedException,
} from '@nestjs/common';
import _ from 'lodash';
@Injectable()
export class BoardService {
  // 데이터베이스를 사용하지 않아 일단은 배열로 구현
  private articles = [];
  // 게시글 비밀번호를 저장하기 위한 Map 객체입니다.
  private articlePasswords = new Map();
  getArticles() {
    return this.articles;
  }
  getArticleById(id: number) {
    return this.articles.find((article) => {
      return article.id === id;
    });
  }
  createArticle(title: string, content: string, password: number) {
    // id 먼저 할당
    // 1번부터 시작 => 현재 배열의 크기 + 1
    const articleId = this.articles.length + 1;
    this.articles.push({ id: articleId, title, content });
    this.articlePasswords.set(articleId, password);
    return articleId;
  }
  updateArticle(id: number, title: string, content: string, password: number) {
    if (this.articlePasswords.get(id) !== password) {
      throw new UnauthorizedException(
        `Article password is not correct. id: ${id}`,
      );
    }
    const article = this.getArticleById(id);
    if (_.isNil(article)) {
      throw new NotFoundException(`Article not found. id: ${id}`);
    }
    article.title = title;
    article.content = content;
  }
  deleteArticle(id: number, password: number) {
    if (this.articlePasswords.get(id) !== password) {
      throw new UnauthorizedException(
        `Article password is not correct. id: ${id}`,
      );
    }
    this.articles = this.articles.filter((article) => {
      return article.id !== id;
    });
  }
}
'코딩캠프 > 내일배움캠프' 카테고리의 다른 글
| [ TIL ] 02.17(금) 68일차 (0) | 2023.02.17 | 
|---|---|
| [ TIL ] 02.16(목) 67일차 (0) | 2023.02.16 | 
| [ TIL ] 02.14(화) 65일차 (0) | 2023.02.14 | 
| [ TIL ] 02.13(월) 64일차 (0) | 2023.02.13 | 
| [ WIL ] 02.06~10 13주차 (0) | 2023.02.12 | 
