NestJs 스터디(1)

연꽃·2022년 2월 15일
2

NestJs

목록 보기
1/7
post-thumbnail

컨트롤러(Controller)

🏀 컨트롤러란?

  • 컨트롤러는 기본적으로 백엔드에서 사용하는 컨트롤러와 하는 일이 같다. 즉, 클라이언트에서 서버로 들어오는 요청을 처리하고 응답을 클라이언트로 반환하는 역할을 한다.
  • 클라이언트의 요청을 받기 위해서는 기본적으로 라우팅이 필요하다. Express에서는 기본적으로 라우팅을 일일이 다 해주었지만(복잡하고 번거롭다), NestJs는 간편하게 컨트롤러에서 라우팅이 가능하다.(매우 편리하다)

🏀 컨트롤러의 사용 - 라우팅

  • 클래스와 데코레이터의 선언으로 가능하다.
  • 데코레이터를 사용해 컨트롤러 클래스에 메타데이터를 입력하면 내부적으로 Nest가 라우팅 맵을 생성하여, 들어오는 요청을 알맞는 컨트롤러로 보낼 수 있게 된다.
  • nest g controller {이름}을 사용하면, 바로 활용가능한 형태의 컨트롤러가 생성된다. 추가적으로 모듈에 등록도 된다.

NestJs 공식문서에 예제를 보면서 구체적으로 살펴보자.

// cats.controller.ts

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

@Controller('cats')
export class CatsController {
  @Get()
  findAll(): string {
    return 'MEOW';
  }
}
  • @Controller('cats') 데코레이터를 통해 컨트롤러임을 명시하고, 라우팅 경로(/cats)를 설정한다.
  • CatsController라는 클래스를 만들고, 클래서 내부에 @Get()과 같은 데코레이터는 특정 HTTP 요청 메서드(GET 등)와 라우팅 경로(/cats 등)에 대한 엔드포인트를 만든다.

이 예제 코드는 GET /cats 요청을 받으면 또한 상태 코드 200과 함께 문자열 MEOW를 응답한다. @Get() 데코레이터에도 인수로 경로 지정이 가능한데, 예를 들어 @Controller('cats')의 @Get('profile')은 GET /cats/profile요청에 대응합니다.

🏀 컨트롤러의 사용 - 요청객체 접근

client의 request 접근이 필요할땐 @Req() 데코레이터를 사용하면 된다. 이 객체는 default로 express의 request 객체를 따른다.

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

@Controller('cats')
export class CatsController {
  @Get()
  findAll(@Req() request: Request): string {
    return 'This action returns all cats';
  }
}
  • Express의 요청 객체에는 쿼리 스트링, 파라미터, HTTP 헤더, 바디 등을 담고 있어 위의 방식으로 처리하는 경우가 많다.
  • 하지만 Nest에서는 요청 객체에 직접 접근할 필요가 거의 없다. 대신에 필요에 따라 @Body(), @Query() 등, 목적에 맞는 데코레이터를 사용하는게 좋다!(처음 네스트를 접했을 때, 네스트 코드만 보고 잘 이해가 되지 않았던 요인들 ㅠㅠ)
  • 추가적으로 핸들러 시그니처에 사용할 수 있는 다양한 데코레이터들은 네스트 공식문서에 잘 정리되어 있으니, 필요할 때 잘 활용해보자!

🏀 컨트롤러의 사용 - 응답 처리

  • 표준 (권장) — 핸들러 메서드가 JavaScript 객체나 배열을 리턴하면 Nest가 이를 JSON 방식으로 직렬화하여 응답한다. 이 방법으로는 아무 값이나 리턴하면 나머지는 Nest가 알아서 응답을 처리해주기에 간편하며, 어떤 웹 서버 라이브러리를 사용하든 신경쓰지 않아도 된다.(매우 편리하다)
  • 웹 서버 라이브러리(플랫폼) 특정 — @Response(별칭 @Res()) 데코레이터를 핸들러 메서드 시그니처의 매개변수에 사용하면 된다.(보통 Express에서 많이 사용하는 방법이며, res.status(200).send()의 형식을 활용하였다.)

🏀 컨트롤러의 사용 - 요청 페이로드와 DTO (@Body())

POST 메서드같은 경우, HTTP 요청의 바디에서 데이터를 받아오는 것이 일반적이다. 이러한 데이터는 Nest의 핸들러 메서드에서 @Body() 데코레이터가 적용된 DTO 타입의 매개변수로 접근할 수 있다!!! DTO(데이터 전달 객체, Data Transfer Object)는 데이터가 네트워크를 통해 어떻게 전달되는지 정의하는 일종의 스키마 객체이며, 클래스로 정의할 수 있습니다.

// create-cats.dto.ts

export class CreateCatDto {
  name: string;
  age: number;
  breed: string;
}

그리고 이렇게 정의한 DTO는 컨트롤러의 핸들러 메서드에서 다음과 같이 사용할 수 있다.

// cats.controller.ts

@Post()
async create(@Body() createCatDto: CreateCatDto) {
  return 'This action adds a new cat';
}

🏀 컨트롤러의 사용 - 비동기 사용

모던 JavaScript에서 데이터를 다루는 일은 비동기적인 경우가 많습니다. 이에 대응하기 위해 Nest는 async 함수를 잘 지원합니다. async 함수는 지연된 결과값인 Promise 객체를 반환합니다. 그러므로 메서드에서 다음과 같이 Promise를 리턴하여도 잘 처리됩니다.

@Get()
async findAll(): Promise<any[]> {
  ...
  return [];
}

🏀 컨트롤러의 사용 - 컨트롤러 등록

컨트롤러를 완성하는 것만으로는 Nest에서 컨트롤러 클래스를 인식하지 못한다.(하지만 위에서 서술한 것처럼 nest g controller {이름}를 통해서 컨트롤러를 만들었다면 자동으로 모듈에 컨트롤러가 등록된다) 컨트롤러는 모듈에 존속되어야하며, 그러려면 모듈 클래스의 @Module() 데코레이터에 controllers 옵션 배열로 컨트롤러를 지정해야합니다.

// app.module.ts

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

@Module({
  controllers: [CatsController],
})
export class AppModule {}

참고: 네스트 공식문서

profile
우물에서 자라나는 중

1개의 댓글

comment-user-thumbnail
2022년 2월 16일

async함수인데 await을 이용하여 리턴하지 않아도 네스트가 알아서 잘해주는게 신기하네요!

답글 달기