Skip to content

Nest.js 로 배우는 백엔드 프로그래밍 Chapter 2

Posted on:August 21, 2023 at 04:03 AM

Chapter 2


**컨트롤러**

NestJS 의 컨트롤러는 MVC 패턴에서 말하는 컨트롤러를 말한다. ( 비즈니스 로직 )

컨트롤러는 들어오는 요청 ( request ) 를 받고, 처리된 결과를 응답 ( response ) 로 돌려주는 인터페이스 역할을 한다.

컨트롤러는 엔드포인트 라우팅 매커니즘을 통해 각 컨트롤러가 받을 수 있는 요청을 분류한다.

컨트롤러를 사용 목적에 따라 구분하면 구조적이고 모듈화된 소프트웨어를 작성할 수 있다.

Nest 에서는 @Query(), @Param(key? : string), @Body() 데코레이터를 이용해서 요청에 포함된 쿼리 매개변수, 패스 ( Path ) , 매개변수 본문을 쉽게 받을 수 있게 해준다.

HTTP 메서드에는 업데이트를 위해 동작을 기술 하는 메서드가 두 가지가 있는데 PUT 은 리소스 전체를 교체할 때 쓰이고, PATCH 는 리소스의 일부를 업데이트 할때 사용한다.

string, number, boolean 과 같은 자바스크립트의 원시 타입을 리턴할 경우에는 직렬화 ( stringify ) 없이, 바로 보내지만, 객체를 리턴한다면 직렬화를 통해 JSON 형식으로 자동 변환해준다.

이 방법이 권장하는 방법이지만, 라이브러리별 응답 객체를 직접 다룰 수도 있다.

앞서 Nest 는 CRUD 에 대해 성공 응답으로 POST는 201, 그외는 200 을 보낸다.

만약 이 상태코드를 다른 값으로 바꾸려면, Nest 에서는 이를 손쉽게 적용할 수 있는

@HttpCode 데코레이터를 이용하면 된다.

**헤더**

만약 응답에 커스텀 헤더를 추가하고 싶다면 @Header ㅔㄷ코레이터를 사용하면 된다.

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

@Header('Custom', 'Test Header')
@Get('id')
findOneWithHeader(@Param('id') id : string) {
  return this.userService.findOne(+id);
}

**리디렉션**

종종 서버가 요청을 처리한 후, 요청을 보낸 클라이언트를 다른 페이지로 이동하고 싶은 경우가 있는데, 이를 리디렉션이라고 한다.

응답 본문에 리디렉션할 URL 을 포함해서 클리이언트가 스스로 페이지를 이동 할 수도 있지만,

@Redirect 데코레이터를 사용하면 쉽게 구현이 가능하다.

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

@Redirect('https://www.leezer-ui.com',301)
@Get(':id')
findOne(@Param('id') id : string ){
  return this.userService.findOne(+id)
}

**라우트 매개변수**

라우트 매개변수는 패스( path ) 매개변수라고도 합니다. 이미 앞선 예제에서 사용했다.

1전 유저의 정보를 가져오려면 https://localhost:3000/users/1 로 요청을 한다.

여기서 1 에 해당하는 부분이 유저 ID 인데 이는 동적으로 구성된다.

즉, 경로를 구성하는 매개변수가 된다. 전달받은 매개변수는 인수에 @Param 데코레이터로 주입받을 수 있다.

라우트 매개변수를 전달받는 방법은 두 가지가 있는데, 먼저 매개변수가 여러 개 전달될경우 객체의 형태로 한번에 받는 방법이다.

이 방법은 params 의 타입이 any 가 되어 권장되지는 않는다. 물론 매개변수의 타입이 항상 string 이기 때문에 명시적으로

{[key : string] : string } 타입을 지정해도 된다.

더 일반적인 방법은 다음 코드처럼 라우팅 매개변수를 따로 받는것 이다.

@Delete(':userId/memo/:memoId')
  deleteUserMemo(
    @Param('userId') userId : string;
    @Param('memoId') memoId : string;
  ) {
     return `userId : ${userId}, memoId: ${params.memoId}`
  }
  }

하위 도메인 라우팅

서버에서 제공하는 기능을 API로 외부에 공개하기로 했다고 가정합시다. 현재 회사가 사용하고 있는 도메인은 example.com 이고, API 요청은 api.example.com으로 받기로 했습니다.

즉, http://example.com http://api.example.com 로 들어온 요청을 서로 다르게 처리하고 싶다고 한다면,

또한 하위 도메인에서 처리하지 못하는 요청은 원래의 도메인에서 처리되도록 하고 싶다고 하자. 이런 경우 하위 도메인 라우팅 기법을 사용할 수 있다.

예를 들어, app.controller.ts 에 이미 루트 라우팅 경로를 가진 엔드포인드가 존재한다면, ApiController 에서도 같은 엔드포인트를 받을 수 있도록 하기 위해 ApiController 가 먼저 처리되도록 순서를 수정해야한다.

@Module({
	// ApiController 가 먼처 처리되도록 한다.
  controllers : [ApiController, AppController],
  ...
})

export class AppModule {}

@Controller 데코레이터는 ControllerOptoins 객체를 인수로 받는데, host 속성에 하위 도메인을 기술하면 된다.

@Controller({ host: 'api.example.com' }) // 하위 도메인 요청 처리 설정
export class ApiController {
  @Get()
  index(): string {
    return 'Hello, API'; // 다른 응답
  }
}

로컬에서 테스트를 하기 위해 하위 도메인을 api.localhost 로 지정하면, curl 명령어가 제대로 동작하지 않습니다. 이는 api.localhost가 로컬 요청을 받을 수 있도록 설정되어 있지 않기 때문인데, 이를 해결하려면

/etc/hosts 파일의 마지막에 127.0.0.1 api.localhost를 추가하고 서버를 다시 구동하면 된다.

// /etc/hosts

127.0.0.1 api.localhost
127.0.0.1 v1.api.localhost

코드는 아래와 같이 바뀌게 된다.

@Controller({host : 'api.localhost'}) // localhost 로 변경
export class ApiController {
  @Get()
  index: string () {
    return 'Hello World'
  }
}

앞서 우리는 요청 패스를 @Param 데코레이터로 받아 동적으로 처리할 수 있었는데, 유사하게 @HostParam 데코레이터를 이용하면, 서브 도메인을 변수로 받을 수 있다.

API 버저닝을 하는 방법은 여러 가지 방법이 있지만, 하위 도메인을 이용하는 방법을 많이 사용한다.

@Controller({ host: ':version.api.localhost' }) // localhost 로 변경
export class ApiController {
  @Get()
  index(@HostParam('version') version: string): string {
    return `Hello, API ${version}`;
  }
}

여기서, host param이 없는 host 로 요청을 하면 기존 도메인으로 요청이 처리되는 것을 볼 수 있다.