티스토리 뷰

728x90
SMALL

배경

nestjs를 예전부터 공부해보고 싶었다. 미뤄두고 있었는데 잠깐 시간이 나서 주말동안 nestjs를 공부해봤다. 그리고 무엇보다 새로운 프로젝트를 만들것인데 써보고 싶은 기술은 모두 써야 후회가 없을 것 같다. 괜찮은 유튜브 강의가 보이길래 그걸 보고 정리해봤다.

 

nestjs 시작하기

nestjs 설치

먼저 전역으로 nestjs cli를 설치해주자

npm i -g @nestjs/cli

 

그리고 다음 명령어를 통해 보일러 플레이트가 세팅된 프로젝트를 만들 수 있다.

nest new project-name 

 

새로운 폴더를 만들지 않고 지금 경로에 만들고 싶다면 다음 명령어를 입력하자

new new ./

 

nestjs cli

다음 명령어로 module, controller, service를 설치할 수 있다. 모듈, 컨트롤러, 서비스 설명은 생략

nest g module boards
nest g controller boards --no-spec
nest g service boards --no-spec

// (no spec은 테스트 제외)

 

provider

provider : 서비스, 레포지토리 등이 provider다. 특징은 종속성으로 주입할 수 있다는 것이다.

의존성 주입을 모른다면 https://ms3864.tistory.com/410 참고

 

controller 사용법

  • get ,post, delete, patch 데코레이터로 감싸주면 라우터가 된다.
  • params, body, query 데코레이터를 이용해서 간편하게 가져올 수도 있다. 인자에 아무것도 넣지 않으면 객체로 가져오고 인자를 넣으면 그 인자를 가져온다.
  • 서비스계층은 특별히 nestjs라고 다른점이 크게 없기 때문에 (inject제외) 설명 생략
@Controller('boards')
export class BoardsController {
  constructor(private readonly boardsService: BoardsService) {}

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

  @Post('/')
  createBoard(@Body() createBoardDto: CreateBoardDto): Board {
    return this.boardsService.createBoard(createBoardDto);
  }

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

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

  @Patch('/:id/status')
  updateBoardStatus(@Param() id: string, @Body() status: BoardStatus) {
    return this.updateBoardStatus(id, status);
  }
}

 

dto

계층 간 데이터 교환을 하기 위해 사용하는 객체이다. 넘겨주는 값이 많아지게 되면 코드를 수정할 때도 힘들고 버그가 나기도 쉽다. dto를 만들어주자

 

pipe

pipe는 data transformation, data validation을 위해서 사용된다.

 

pipe level

  • handler level pipe
  @Post('/')
  @UsePipes(ValidationPipe)
  createBoard(@Body() createBoardDto: CreateBoardDto): Board {
    return this.boardsService.createBoard(createBoardDto);
  }
  • parameter level pipe
@Post('/a')
createBoard(@Body('title', ParameterPype) title)
  • global level pipe
app.useGlobalFilters(GlobalPype)

 

built in pipes

이미 만들어져있는 파이프들이 있다.

  @Post('/')
  @UsePipes(ValidationPipe)
  createBoard(@Body() createBoardDto: CreateBoardDto): Board {
    return this.boardsService.createBoard(createBoardDto);
  }
  • validation pipe
  • parseint pipe
  • parsebool pipe
  • parse array pipe
  • parse uuid pipe
  • defaultvalue pipe

 

커스텀 파이프

PiepeTransform을 implement해야한다. 

그리고 transform에서 유효성 검증이나 값을 변환해준다.

 

pipe

import { BadRequestException, PipeTransform } from '@nestjs/common';
import { BoardStatus } from '../board.model';

export class BoardStatusValidationPipe implements PipeTransform {
  readonly StatusOptions = [BoardStatus.PRIVATE, BoardStatus.PUBLIC];

  transform(value: any) {
    value = value.toUpperCase();

    if (!this.isStatusValid(value)) {
      throw new BadRequestException(`${value} isn't in the status options`);
    }

    return value;
  }

  private isStatusValid(status: any) {
    return this.StatusOptions.includes(status);
  }
}

controller

  @Patch('/:id/status')
  updateBoardStatus(
    @Param('id') id: string,
    @Body('status', BoardStatusValidationPipe) status: BoardStatus,
  ) {
    return this.boardsService.updateBoardStatus(id, status);
  }

 

Exception

nest에서는 Exception이 굉장히 여러가지가 있다.

두가지의 인자를 전달할 수 있는데 아무것도 전달하지 않으면 statusCode, message를 return한다. 

첫번째 인자만 전달하면 message값이 생겨나고 기존에 있던 message는 error가 된다.

두번째 인자도 전달하면 그 값이 error값이 된다.

 

ex)

인자 전달 x

{
    "statusCode": 400,
    "message": "Bad Request"
}

첫번째 인자만 전달

{
    "statusCode": 400,
    "message": "PU2BLIC isn't in the status options",
    "error": "Bad Request"
}

첫번째, 두번째 인자 전달

{
    "statusCode": 400,
    "message": "PU2BLIC isn't in the status options",
    "error": "public or private"
}

 

typeorm

다음 명령어로 typeorm을 설치하자. 2022.4.24기준 0.2버전을 설치해야한다. 이런건 날짜에 따라 바뀌기 때문에 공식문서를 찾아보자

yarn add @nestjs/typeorm
yarn add typeorm@0.2

 

typeorm에 대한 기본 설명은 생략한다. 이건 typeorm글이 아니기 때문에... 모른다면 https://ms3864.tistory.com/390 를 참조

간단한 예시 코드만 적어두겠다.

 

entity

import { BaseEntity, Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
import { BoardStatus } from './board-status.enum';

@Entity()
export class Board extends BaseEntity {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  title: string;

  @Column()
  description: string;

  @Column()
  status: BoardStatus;
}

repository

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

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

 

jwt

나중에 써야지...

 

미들웨어 순서

middleware -> guard -> interceptor(before) -> pipe -> controller -> service -> controller -> interceptor(after) -> filter(if applicable) -> client

 

log

express에서는 winston으로 로그를 찍었는데 nest에는 이미 내장되어있다.

log - 중요한 정보의 범용 로깅

warning - 치명적이거나 파괴적이지 않은 처리되지 않은 문제

error - 치명적이거나 파괴적인 처리되지 않은 문제

debug - 오류 발생시 로직을 디버그하는 데 도움이되는 유용한 정보(개발자용)

verbose - 응용 프로그램의 동작에 대한 통찰력을 제공하는 정보(운영자용)

 

config

보통 나는 dotenv를 설치해서 했는데 nestjs에서 만든것이 있다. dotenv를 내부에서 사용했다고 하던데.. 그냥 dotenv를 이용해도 상관없지만 그래도 한번 따라해봤다. 

 

다음명령어로 설치하고

yarn add @nestjs/config

 

app.module에 이렇게 적용하면 된다.

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';

@Module({
  imports: [ConfigModule.forRoot()],
})
export class AppModule {}

 

설정이 몇개있는데 공식문서를 읽어보자. 나는 전역상태와 env파일 분기처리만 해줬다.

    ConfigModule.forRoot({
      isGlobal: true,
      envFilePath: `.env.${process.env.NODE_ENV}`,
    }),

 

https://docs.nestjs.com/techniques/configuration

 

Documentation | NestJS - A progressive Node.js framework

Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Progamming), FP (Functional Programming), and FRP (Functional Reac

docs.nestjs.com

 

후기

기본적인 것만 해봤는데 나쁘지 않다. 그리고 기존에도 express로 계층을 나눠서 사용했는데 크게 다른점이 없었다. 익숙하지 않아서 조금 불편하기는 하지만 적응만 되면 훨씬 좋을 것 같다. throw error부분도 되어있어서 훨씬 편하다. express로 프로젝트를 만들면서 고민하고 적용했던 것들이 대부분 이미 구현되어 있었다.

글 제목이 nestjs 시작하기라서 정말 입문자분들이 이 글을 볼수도 있을텐데 처음부터 백엔드를 nestjs로 시작하는 건 별로인 것 같다.(내가 입문자들이 이해할 수 있을정도로 글을 친절하게 쓰지도 않았다.) 백엔드로 기본적인 계층이나 에러처리 등을 할 수 있을 때 nestjs로 넘어가는 걸 추천한다. 그래도 공부하고 싶다면 아래 영상을 보자. 나름 친절하게 준다. 그런데 이걸 정말 초심자가 이해할 수 있을지는 모르겠다.

 

 

 

참조영상

https://www.youtube.com/watch?v=3JminDpCJNE&ab_channel=JohnAhn 

 

728x90
LIST
댓글
공지사항