• Home
  • About
    • Pieces for Studying photo

      Pieces for Studying

      Moon is a minimal, one column jekyll theme.

    • Learn More
    • Email
    • LinkedIn
    • Github
  • Posts
    • All Posts
    • Baekjoon
    • CS231N
    • Study
  • Projects

[Node] Nestjs 정리 - 1. Controller, Provider

20 Jan 2021

Reading time ~3 minutes

1. Introduction

NestJS는 nodejs 위에서 서버 어플리케이션을 구축할 수 있는 프레임워크 이다. 기본적으로 Express의 API를 사용하고 Fastify로도 구성할 수 있다.

기존의 Express 는 서버를 빠르게 개발할 수 있었지만 Architecture 라는 중요한 문제점을 해결하지 못했다.

반대로 NestJS는 Typescript을 도입하고 객체지향적인 요소들을 사용하고 Dependency Injection 등 패턴을 가져와 개발의 효율성을 높여줄 수 있다. Spring 은 써보지 않았지만 이런 점에서 Spring과 비슷하다고 하는 것 같다.

Setup

간단히 Nest CLI를 이용하여 프로젝트를 구성할 수 있다.

npm install -g @nestjs/cli
nest new PROJECT

2. Controller

Controller는 클라이언트의 HTTP 요청을 받아 응답을 리턴해주는 역할 을 한다.

보통 Controller는 여러개의 라우팅 경로를 가지며 각 경로들은 각각 다른 행동들을 수행한다.

Controller을 만들기 위해서는 @Controller 라는 데코레이터가 필요하다.

import { Controller, Get } from '@nestjs/common';

@Controller('cats')
export class CatsController {
  @Get(:id)
  findOne(@Param('id') id: string) {
    return ...
  }
}

우선 @Controller 데코레이터로 해당 클래스가 Controller 역할을 하도록 만들고 그 안에 @Get 등 HTTP Method 들을 데코레이터를 이용해 구현할 수 있다. 위의 코드는 /cats/:id 로 들어오는 GET 요청들을 처리하는 라우팅 핸들러인 findOne 함수를 구현한 것이다.

NestJS의 컨트롤러는 두가지 방식을 통해 클라이언트에 응답을 제공한다. 첫번째는 NestJS에서 빌트인으로 제공하는 방식으로, 함수가 Object 또는 Array를 반환하면 NestJS에서 자체적으로 JSON 형태로 Serialize 해서 응답한다. 반대로 string, number, boolean 같은 값들은 Serialize 하지 않고 그냥 응답한다. 이런 방식은 값만 리턴해주고 나머지는 NestJS에 맡김으로서 편리하게 사용할 수 있다.

두번째 방식으로는 Library-specific 방식으로 사용하는 라이브러리(기본적으로 Express) 의 Request, Response 객체를 사용하는 것이다. 해당 방식을 사용하려면 데코레이터를 이용하여, findAll(@Req() req, @Res() res) .. res.status(200).send() 이렇게 직접 Express의 객체를 이용하여 응답을 구성할 수도 있다. 또한 기본적으로 Controller는 POST 요청에는 201, 나머지 요청들에는 200을 응답한다. 이 부분을 커스텀 하고 싶다면 @HttpCode 데코레이터를 이용하여 변경할 수도 있다.

이외에도 @Body() @Query() 등 다양한 데코레이터를 사용하여 핸들러를 구성할 수도 있다.

DTO (Data Transfer Object)

POST 요청의 경우 서버는 Body도 함께 받는 경우가 대부분이다. 이럴 때 Body 가 어떤 오브젝트여야 하는지 미리 정의해 두는 것이 DTO 이다. NestJS는 자바스크립트의 class를 이용하여 정의한다.

export class CreateCatDto {
  name: string;
  ...
}
@Post()
async create(@Body() createCatDto: CreateCatDto) {
  return ...
}

이런 식으로 구성함으로써 Request Body가 유효한지는 Pipe에 위임하여 검증할 수 있고, 컨트롤러의 핸들러는 단지 요청을 받아서 응답만 반환해주면 되게 구현할 수 있다.

3. Provider

NestJS 에서의 기초가 되는 개념이 바로 Provider 이다. 대부분의 Service, Repository 등 대부분의 NestJS 클래스들이 Provider 이다. Provider는 @Injectable() 데코레이터를 이용한 클래스로, 다른 클래스에 Dependecy 로 등록되거나 다른 Provider를 Dependecy 로 등록할 수 있다.

Component

위의 사진은 Controller 과의 Dependency들을 보여준다. NestJS는 Dependency 들을 SOLID 원칙에 따라 설계하는것을 추천한다고 한다.

위에서의 Controller는 자신의 역할인 요청을 받고 응답을 하기만 하고, 나머지 부분들은 Service, Pipe, Middleware 등 Provider 들을 Dependency 로 받아 처리한다.

Service

Service는 Controller 에 Dependecy로 사용되며, 구체적으로 디비에 접근하는 등 요청을 처리하는 역할을 한다.

import { Injectable } from '@nestjs/common';
import { Cat } from './interfaces/cat.interface';

@Injectable()
export class CatsService {
  private readonly cats: Cat[] = [];

  create(cat: Cat) {
    this.cats.push(cat);
  }

  findAll(): Cat[] {
    return this.cats;
  }
}

위에서 구현한 CatsService는 이제 Provider 로써 CatsController 에 Dependecy 로 주입(Injection) 되게 된다.

@Controller('cats')
export class CatsController {
  constructor(private catsService: CatsService) {}

Provider registration

이제 마지막으로 Module 에서 CatsService가 Provider 로 사용될 수 있도록 등록해 주어야 한다.

import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';

@Module({
  imports: [...],
  controllers: [CatsController],
  providers: [CatsService],
})
export class CatModule {}

References

  • Documentation - NestJS


studybackendnodenestjs Share Tweet +1