NestJS 帶你飛! 시리즈 번역 03# Controller (상)

2023. 5. 29. 18:42개발 문서 번역/NestJS

728x90
이 포스팅은 「NestJS 기초실무 가이드 : 강력하고 쉬운 Node.js 웹 프레임워크로 웹사이트 만들기」
(서명: NestJS 基礎必學實務指南:使用強大且易擴展的 Node.js 框架打造網頁應用程式)
책이 출간되었습니다. 

 

Nest의 세상에서는 Controller가 라우팅/프론트 단에서 넘어온 요청을 처리합니다.

Controller는 각기 다른 목적의 요청들을 HTTP Method Resource를 통해 처리하는데요.

웨이터가 자리 안내를 해주고, 손님의 요구를 들어주는 등의 행위와 같습니다. 

또한 프론트단의 요청에 알맞은 응답도 해줍니다.

전체적으로 보면 Controller는 프론트단의 요청을 처리하며, 비슷한 성질의 리소스들이 합쳐진 컴포넌트와 같다고 할수 있겠습니다.

 

Controller 만들기

먼저 Controller는 @Controller 데코레이터를 통해 정의해줍니다. NestCLI를 통해 빠르게 Controller를 생성할 수 있으며 명령어는 다음과 같습니다.

$ nest generate controller <CONTROLLER_NAME>
주의 : <CONTROLLER_NAME>은 경로를 포함할 수 있습니다. (ex : features/todo, src폴더 안에 경로가 포함된 Controller가 생성됩니다. )

이 포스팅에서는 todo 라는 Controller를 만들어보겠습니다. :

$ nest generate controller todo

src 아래에 todo라는 폴더가 생긴걸 확인할 수 있습니다. 안에는 todo.controller.tstodo.controller.spec.ts 파일이 생성되었습니다.

Controller만 생성했으니 자동으로 루트 모듈에 이 Controller가 import 되었을텐데, 이는 다시말해서 AppModule이 자동으로 TodoController를 import 했음을 의미합니다.

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TodoController } from './todo/todo.controller';

@Module({
  imports: [],
  controllers: [AppController, TodoController],
  providers: [AppService],
})
export class AppModule {}

라우팅

Controller의 뼈대가 세워졌습니다.
todo.controller.ts@Controller 데코레이터에 문자열 todo가 생긴걸 확인할 수 있는데요.

이를 라우팅의 접두사(prefix, 前綴) 라고 부릅니다.

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

@Controller('todo')
export class TodoController {}
주의 : NestCLI를 통해 생성한 Controller의 접두사는 해당 Controller의 이름을 기본값으로 합니다. 일반적으로 이름을 단수로 입력하여 생성하며 접두사는 복수로 바꿔 사용합니다.

라우팅 접두사를 추가하면 비슷하게 라우팅되는 자원에 대해모두 같은 Controller에 속하게 할 수 있다는 장점이 있습니다.

예를 들어보겠습니다.

/todos 라는 Controller가 있으면, id를 인자로 받아 PATCH / DELETE 작업을 수행하고

/todos 라는 경로로 GET POST 작업을 처리할 수 있습니다.

 

 

Http Methods

class 메서드에 데코레이터를 추가하는 방법으로 각기 다른 Http Method를 호출할 수 있습니다.

Nest는 Controller와 지정된 Http Methods 데코레이터로 라우팅 테이블을 만듭니다.
아래의 코드는 그 예제이며, GET 메서드를 사용하였습니다.

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

@Controller('todos')
export class TodoController {
  @Get()
  getAll() {
    return [];
  }
}

서버를 가동하고 http://127.0.0.1:3000/todos 에 접속해보면 결과를 확인할 수 있습니다. 결과값으로는 빈 배열이 나옵니다.

Nest의 Http Method 데코레이터를 정의하는 방법은 일반 Http Method를 정의하는 방법과 동일합니다.

  • @Get: 해당 라우팅은 GET 요청으로 발생됨을 의미합니다.
  • @Post: 해당 라우팅은 POST 요청으로 발생됨을 의미합니다.
  • @Put: 해당 라우팅은 PUT 요청으로 발생됨을 의미합니다.
  • @Patch: 해당 라우팅은 PATCH 요청으로 발생됨을 의미합니다.
  • @Delete: 해당 라우팅은 DELETE 요청으로 발생됨을 의미합니다.
  • @Options: 해당 라우팅은 OPTIONS 요청으로 발생됨을 의미합니다.
  • @Head: 해당 라우팅은 HEAD 요청으로 발생됨을 의미합니다.
  • @All: 해당 라우팅은 어떠한 요청방식이든 상관 없이 발생됨을 의미합니다.

 

하위 라우팅

라우팅을 설계할 때 높은 확률로 서브 라우팅에 대해 생각해보아야 하는데요. (예: /todos 아래 다음 자원을 명시해야할 때) 이 포스팅에서는 GET /todos/examples라고 정의를 해보겠습니다.

하지만 이럴때마다 매번 같은 라우터를 생성할 수도 없습니다.

이럴때 바로 하위 라우팅을 이용하면 됩니다. Http Method 데코레이터를 통해 하위 라우팅을 지정할 수 있으며

이는 Controller에서 설정한 접두사가 앞에 자동으로 붙습니다. 아래는 예제이며 GET /todos/examples로 라우팅됩니다.

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

@Controller('todos')
export class TodoController {
  @Get('/examples')
  getExample() {
    return [
      {
        id: 1,
        title: 'Example 1',
        description: '',
      },
    ];
  }
}

http://127.0.0.1:3000/todos/examples 에 접속하면 아래와 같은 결과를 확인할 수 있습니다.

라우팅 파라미터 구성하기

라우팅 파라미터를 구성하는 방법은 간단합니다.

Http Method 데코레이터에 정의를 하면 되는데, 이때 문자열 양식은 :<PARAMETER_NAME>으로 정의할 수 있습니다.

이 방법으로 정의할 때에는 메서드에 @Param 데코레이터의 파라미터를 추가해주어야 하는데요.

이렇게 하면 쉽게 라우팅 파라미터를 받아올 수 있습니다. 아래는 id 파라미터를 추가한 라우터입니다.

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

@Controller('todos')
export class TodoController {
  @Get(':id')
  get(@Param() params: { id: string }) {
    const { id } = params;
    return {
      id,
      title: `Title ${id}`,
      description: ''
    };
  }
}

이런 방법으로도 라우팅 파라미터를 정의할 수 있습니다. 

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

@Controller('todos')
export class TodoController {
  @Get(':id')
  get(@Param('id') id: string) {
    return {
      id,
      title: `Title ${id}`,
      description: ''
    };
  }
}

http://127.0.0.1:3000/todos/1 에 들어가면 아래와 같은 결과를 확인할 수 있습니다.

쿼리 파라미터 (Query Parameters)

쿼리 파라미터와 라우팅 파라미터의 값을 얻는 방법은 서로 비슷합니다.
하지만 Http Method 데코레이터 안에 어떠한 것도 입력할 필요가 없다는건데,
쉽게말해 메서드의 @Query 파라미터 안에만 값을 넣으면 된다는 얘깁니다.

아래는 예제입니다.

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

@Controller('todos')
export class TodoController {
  @Get()
  getList(@Query() query: { limit: number, skip: number }) {
    const { limit = 30, skip = 0 } = query;
    const list = [
      {
        id: 1,
        title: 'Title 1',
        description: ''
      },
      {
        id: 2,
        title: 'Title 2',
        description: ''
      }
    ];

    return list.slice(skip, limit);
  }

}

위처럼 해도 되고, 아래처럼 특정 파라미터만 값을 얻을수도 있습니다.

@Query 데코레이터를 통해 파라미터 이름을 정의합니다.

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

@Controller('todos')
export class TodoController {
  @Get()
  getList(
    @Query('limit') limit: number = 30,
    @Query('skip') skip: number = 0
  ) {
    const list = [
      {
        id: 1,
        title: 'Title 1',
        description: ''
      },
      {
        id: 2,
        title: 'Title 2',
        description: ''
      }
    ];

    return list.slice(skip, limit);
  }
}

브라우저를 통해 http://127.0.0.1:3000/todos?limit=1에 접속하게되면 아래와 같은 결과를 확인할 수 있습니다.

Http 상태 코드

일반적인 상황이라면 POST를 통해 201을 반환 받거나 대다수의 Http Method는 200을 반환 받습니다.

하지만 실제로 해당 동작에 맞는 Http 상태 코드를 반환하고 싶을때가 많을것입니다.

Nest는 Http Code의 enum을 지원하며 데코레이터를 통해 반환될 상태 코드를 지정할 수 있습니다.

아래는 예제 코드입니다.

import { Controller, Patch, HttpCode, HttpStatus } from '@nestjs/common';

@Controller('todos')
export class TodoController {
  @Patch()
  @HttpCode(HttpStatus.NO_CONTENT)
  get() {
    return [];
  }
}

204가 반환된 모습을 확인할 수 있습니다.

 

정리

오늘 배운 내용이 조금 많습니다. 아래에 간단히 요약하여 정리하겠습니다.

1. Controller는 라우팅, 프론트단의 요청을 처리합니다.

2. Controller는 같은 경로의 자원을 합쳐주는 역할을 하며, 하위 라우팅을 포함합니다.

3. Http Method 데코레이터를 통해 쉽게 자원을 처리할 수 있습니다.

4. @Param 데코레이터를 통해 라우팅 파라미터를 받고, @Query 데코레이터를 통해 라우팅 파라미터를 받을 수 있습니다.

5. @HttpCodeHttpStatus를 사용해 자원의 반환 상태코드를 지정할 수 있습니다.

 

이 외에도 Controller의 기능은 엄청 많습니다. 같은 포스팅에 전부 쓰면 내용이 엄청 길어지기 때문에

두 편으로 나누어 포스팅하겠습니다.