[2024.06.28 TIL] 내일배움캠프 52일차 (Nest.js 강의 시청, 게시판 실습)

My_Code·2024년 6월 28일
0

TIL

목록 보기
67/112
post-thumbnail

본 내용은 내일배움캠프에서 활동한 내용을 기록한 글입니다.


💻 TIL(Today I Learned)

📌 Today I Done

✏️ 프로젝트 세팅

  • Nest.js 게시판 프로젝트 생성
nest new nestjs_board

  • 프로젝트 필수 패키지 설치
npm i @nestjs/mapped-types class-validator

  • JavaScript로 코딩시 유용하게 사용할 수 있는 유틸성 패키지인 lodash 패키지 설치
npm i lodash @types/lodash

  • tsconfig.json 파일에 "esModuleInterop": true 항목 추가
  • ES6 모듈 사양을 준수하여 CommonJS 모듈을 가져올 수 있게 함
{
  "compilerOptions": {
    "module": "commonjs",
    "declaration": true,
    "removeComments": true,
    
    ...
    
    "forceConsistentCasingInFileNames": false,
    "noFallthroughCasesInSwitch": false,
    "esModuleInterop": true
  }
}

✏️ DTO란?

  • DTO (Data Trasfer Object)는 간단하게 말하면 데이터를 전송하기 위해 작성된 객체를 의미

  • 전송되는 데이터에 대한 유효성 검사를 진행할 수 있음

  • 계층(컨트롤러 - 서비스)간 데이터를 전송하는 데 사용됨 (계층 간 결합도를 낮출 수 있음)

  • Nest.js에서는 모든 데이터가 DTO를 통해 운반됨


✏️ 게시판 뼈대 구성하기

  • 게시판 뼈대 한 번에 완성하기
  • 이 명령어를 통해서 post 모듈이 생성되고, 모듈을 구성하는 DTO, 엔티티, 컨트롤러, 서비스가 자동으로 만들어짐
nest g resource post

  • 게시판 빌드
npm run build

  • 게시판 실행
npm run start:dev

✏️ create-post.dto.ts 코드 구현

import { IsNotEmpty, IsNumber, IsString } from 'class-validator';

// 게시물 생성시 입력되는 데이터의 검증 진행
export class CreatePostDto {
  @IsString()
  @IsNotEmpty({ message: '게시물의 제목을 입력해주세요.' })
  readonly title: string;

  @IsString()
  @IsNotEmpty({ message: '게시물의 내용을 입력해주세요.' })
  readonly content: string;

  @IsNumber()
  @IsNotEmpty({ message: '게시물의 비밀번호를 입력해주세요.' })
  readonly password: number;
}

✏️ update-post.dto.ts 코드 구현

  • 게시물을 수정할 때는 내용(content)만 수정한다고 가정

  • 그럼 CreatePostDto를 상속받아서 제목(title)만 제외한 나머지만 입력받으면 됨

  • 제목(title)를 제외하기 위해서 OmitType타입을 이용해서 특정 데이터를 제외하고 상속

import { OmitType } from '@nestjs/mapped-types';
import { CreatePostDto } from './create-post.dto';

export class UpdatePostDto extends OmitType(CreatePostDto, ['title']) {}

✏️ remove-post.dto.ts 코드 구현

  • 게시물 삭제는 생성과 수정과는 다르게 비밀번호(password)만 있으면 그 비밀번호를 통해서 인증된 사용자인지 검증함

  • 그래서 수정과는 반대로 비밀번호(password)만 있으면 되기 때문에 PickType타입을 이용해서 특정 데이터만 상속

import { PickType } from '@nestjs/mapped-types';
import { CreatePostDto } from './create-post.dto';

export class RemovePostDto extends PickType(CreatePostDto, ['password']) {}

✏️ post.service.ts 전체 코드

  • DTO 객체를 어떻게 사용하는지 확인하는 것이 중요함

  • 아직까지는 로컬 저장소를 사용하기 때문에 서버 재실행 시 저장했던 데이터는 날라감

import _ from 'lodash';

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

import { CreatePostDto } from './dto/create-post.dto';
import { UpdatePostDto } from './dto/update-post.dto';
import { RemovePostDto } from './dto/remove-post.dto';

@Injectable()
export class PostService {
  private articles: { id: number; title: string; content: string }[] = [];
  private articlePasswords = new Map<number, number>();

  // 게시물 생성
  create(createPostDto: CreatePostDto) {
    const { title, content, password } = createPostDto;
    const length = this.articles.length;
    const id = length === 0 ? 1 : this.articles[length - 1].id + 1;

    this.articles.push({ id, title, content });
    this.articlePasswords.set(id, password);
    return { id };
  }

  // 게시물 목록 조회
  findAll() {
    return this.articles.map(({ id, title }) => ({ id, title }));
  }

  // 게시물 상세 조회
  findOne(id: number) {
    return this.articles.find((article) => id === article.id);
  }

  // 게시물 수정
  update(id: number, updatePostDto: UpdatePostDto) {
    const { content, password } = updatePostDto;

    const existArticle = this.articles.find((article) => article.id === id);
    // isNil() 메서드는 값이 null이거나 undefined면 true를 반환
    if (_.isNil(existArticle)) {
      throw new NotFoundException('게시물이 존재하지 않습니다.');
    }

    const articlePassword = this.articlePasswords.get(id);
    if (!_.isNil(articlePassword) && articlePassword !== password) {
      throw new NotFoundException('비밀번호가 일치하지 않습니다..');
    }

    existArticle.content = content;
  }

  // 게시물 삭제
  remove(id: number, removePostDto: RemovePostDto) {
    const { password } = removePostDto;

    const article = this.articles.find((article) => article.id === id);
    if (_.isNil(article)) {
      throw new NotFoundException('게시물이 존재하지 않습니다.');
    }

    const articlePassword = this.articlePasswords.get(id);
    if (!_.isNil(articlePassword) && articlePassword !== password) {
      throw new NotFoundException('비밀번호가 일치하지 않습니다.');
    }

    const articleIndex = this.articles.indexOf(article);
    this.articles.splice(articleIndex, 1);
    this.articlePasswords.delete(id);
  }
}

✏️ post.controller.ts 코드 구현

  • 기존 Express 프로젝트에서의 라우터와 컨트롤러의 역할을 같이 하고 있음

  • DTO 객체를 통해서 사용자에게 받은 입력 값을 postService에게 넘김

import {
  Body,
  Controller,
  Delete,
  Get,
  Param,
  Patch,
  Post,
} from '@nestjs/common';

import { CreatePostDto } from './dto/create-post.dto';
import { RemovePostDto } from './dto/remove-post.dto';
import { UpdatePostDto } from './dto/update-post.dto';
import { PostService } from './post.service';

@Controller('post') // 주소상에서 /post를 사용하면 이 컨트롤러를 사용
export class PostController {
  constructor(private readonly postService: PostService) {}

  @Post()
  // @Body 데코레이터는 사용자에게 CreatePostDto를 통해서 입력을 받기 위해 사용함
  create(@Body() createPostDto: CreatePostDto) {
    return this.postService.create(createPostDto);
  }

  @Get()
  findAll() {
    return this.postService.findAll();
  }

  // 주소상에서 /post/1 처럼 path parameter를 사용한다는 의미
  // GET http://localhost:3000/post/1
  @Get(':id')
  // 실제로 path parameter를 사용하기 위해서는 @Param 데코레이터가 필요함
  findOne(@Param('id') id: string) {
    return this.postService.findOne(+id);
  }

  // PATCH http://localhost:3000/post/1
  @Patch(':id')
  update(@Param('id') id: string, @Body() updatePostDto: UpdatePostDto) {
    return this.postService.update(+id, updatePostDto);
  }

  // DELETE http://localhost:3000/post/1
  @Delete(':id')
  remove(@Param('id') id: string, @Body() deletePostDto: RemovePostDto) {
    return this.postService.remove(+id, deletePostDto);
  }
}


📌 Tomorrow's Goal

✏️ 개인과제 기본 설계 및 코드 구현

  • Nest.js 프로젝트 생성, 깃허브 연결 등과 같은 기본적인 프로젝트 세팅을 진행할 예정

  • 그리고 프로젝트에 대한 ERD와 API 명세서도 구상해서 작성할 예정

  • 기본적인 설계 뿐만 아니라 세팅한 것들이 잘 돌아가는지 웹 서버를 구동할 예정

  • 가능하다면 추가적인 몇가지 API도 구현할 예정

  • 일단 주말 안으로 진행할 예정



📌 Today's Goal I Done

✔️ Nest.js 강의 시청

  • 3주차 내용은 간단한 게시판 프로젝트 실습을 진행하는 것임

  • 아직 구조적으로 모든 걸 파악하기는 어렵지만 코드에 주석을 달면서 조금씩 이해하고 있음

  • 특히 DTO라는 구조는 처음 알았기 때문에 신선하고 생각보다 편리했음

profile
조금씩 정리하자!!!

0개의 댓글