컨트롤러(Controller)의 목적은 특정 request를 처리하고 클라이언트에 response를 반환하는 역할을 하는 핵심합니다. 컨트롤러(Controller)는 클라이언트로부터 들어온 GET, POST, PUT, DELETE 등의 HTTP requset를 처리하며, 각 요청을 적절한 핸들러 메서드에 매핑하여 response를 반환합니다. 이러한 과정은 라우팅 메커니즘을 통해 이루어집니다.

컨트롤러(Controller)를 생성하기 위해서는 데코레이터(decorator)를 사용합니다. 데코레이터(decorator)는 클래스에 필요한 메타데이터와 연결하고 Nest가 라우팅 맵을 생성할 수 있도록 합니다.
HINT
Nest에서 사용되는 데코레이터(decorator)는 메타프로그래밍을 지원하는 TypeScript 기능을 기반으로 하며, 클래스, 메서드, 프로퍼티, 매개변수 등에 추가적인 기능**을 정의할 수 있도록 돕는 기능입니다.
→ [Controller 정의]
컨트롤러(Controller)를 정의하기 위해서는 @Controller 데코레이터를 사용합니다. @Controller는 특정 prefix(경로 접두사)를 설정하여 해당 경로와 관련된 모든 라우터를 처리할 수 있습니다.
예를 들어, 고양이 엔티티와 상호작용하는 모든 라우트를 /cats 경로 아래에 그룹화할 수 있습니다.
// cats.controller.ts
import { Controller, Get } from '@nestjs/common';
@Controller('cats')
export class CatsController {
@Get()
findAll(): string {
return 'This action returns all cats';
}
}
여기서 @Get() 데코레이터는 HTTP GET 요청을 처리하는 핸들러 메서드인 findAll() 을 정의합니다.
→ [라우트 경로]
@Get, @Post, @Put, @Delete, etc…)에 지정된 경로를 결합하여 라우트가 결정됩니다.@Controller(’cats’)와 @Get(’bread’)를 결합하면 GET/cates/bread 라우트가 생성됩니다.→ [표준 응답 처리(recommended)]
string, number, boolean)을 반환할 경우에는 Nest는 직렬화를 시도하지 않고 기본 값을 반환합니다.@HttpCode(...) 데코레이터를 통해 상태 코드를 변경할 수 있습니다.→ [라이브러리별 응답 처리]
response object를 직접 사용할 수 있습니다. 이를 위해 @Res() 데코레이터를 사요합니다.@Get()
findAll(@Res() resposne) {
return response.status(200).send('This action returns all cats')
}
@Res()데코레이터를 사용하면 표준 응답 처리 방식이 비활성됩니다. 만약 response object를 사용하면서도 나머지 처리를 Nest에 맡기고 싶다면, @Res({ passthrough: true }) 옵션을 사용할 수 있습니다.HINT
Nest CLI 명령어를 사용해서 쉽게 컨트롤러를 생성할 수 있습니다.
$ nest g controller [name]명령어를 실행하기만 하면 됩니다.
Nest는 기본적으로 Express나 Fastify 등의 플랫폼에서 requset object(요청 객체)를 처리하며, @Req() 데코레이터를 사용해서 핸들러에서 직접 요청 객체에 접근할 수 있습니다.
// cats.controller.ts
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';
}
}
HINT
위 예제처럼request: Request타입을 추가하기 위해서 express 타입을 활용할 수 있는@types/express패키지를 설치하세요.
@Req() 데코레이터를 사용한 요청 객체(request object)는 HTTP 요청을 나타내며 requset query string, parameters, HTTP headers 및 body에 대한 프로퍼티를 가지고 있습니다. 대부분의 경우 이런 속성을 수동으로 가져올 필요 없이 @Body(), @Query(), @Param() 등의 데코레이터를 통해 즉시 사용할 수 있습니다. 아래는 Nest에서 제공하는 요청 객체(Request object) 데코레이터입니다.
@Request(), @Req() | req |
|---|---|
@Response(), @Res()* | res |
@Next() | next |
@Session() | req.session |
@Param(key?: string) | req.params / req.params[key] |
@Body(key?: string) | req.body / req.body[key] |
@Query(key?: string) | req.query / req.query[key] |
@Headers(name?: string) | req.headers / req.headers[name] |
@Ip() | req.ip |
@HostParam() | req.hosts |
응답 객체(response object)를 사용할 때는 @Res() 또는 @Response 데코레이터를 통해 기본 HTTP 플랫폼(Express 및 Fastify) 응답 객체를 직접 관리할 수 있습니다. @Res() 또는 @Response를 사용하면 Nest 라이브러리 전용 모드(Library-specific)로 전환하고 응답(Response)을 관리할 책임이 사용자에게 있다는 점을 유의하세요. 라이브러리 전용 모드를 사용하게 된다면 response 객체(예: res.json(...) 또는 res.send(...))를 호출하여 응답을 보내야 하며, 그렇지 않으면 HTTP 서버가 중단됩니다.
Nest에서는 HTTP 메서드 데코레이터(@Get(), @Post(), @Put(), @Delete(), @Patch(), @Options(), @Head())를 통해 리소스 엔트포인트를 정의할 수 있습니다. , 또한 @All데코레이터는 모든 메서드를 처리하는 에든포인트를 정의할 수 있습니다.
import { Controller, Get, Post } from '@nestjs/common';
@Controller('cats')
export class CatsController {
@Get()
findAll(): string {
return 'This action returns all cats';
}
@Post()
create(): string {
return 'This action adds a new cat';
}
@Put()
modify(): string {
return 'This action modify a cat';
}
@Delete()
delete(): string {
return 'This action delete a cat';
}
}
엔드포인트에 와이드카드 경로를 사용하면 어떠한 문자 조합과도 메서드를 일치시킬 수 있습니다.
@Get('ab*cd')
findAll() {
return 'This route uses a wildcard';
}
ab*dc 라우트 경로는 abcd, ab_cd, adecd 등과 일치합니다. 문자 ?, +, *, ()는 라우트 경로에 사용할 수 있으며 정규표현식입니다. 하이픈(-),과 점(.)은 문자 그대로 해석됩니다.
HINT
Express에서만 중간 와이드카드가 지원된다는 점을 유의하세요.
응답 상태 코드는 기본적으로 201인 POST 요청을 제외하고 항상 200입니다. 핸들러 수준에서 @HttpCode(...)데코레이터를 추가하면 쉽게 응답 상태 코드를 변경할 수 있습니다.
@Post()
@HttpCode(204)
create() {
return 'This action adds a new cat';
}
HINT
@nestjs/common패키지에서HttpCode를 가져옵니다.
상태 코드는 정적이지 않은 경우 @Res 또는 @Response데코레이터를 사용해서 라이브러리별로 응답 객체를 사용할 수 있으며, 오류가 발생하면 예외를 발생시킬 수 있습니다.
@Header 데코레이터 또는 @Res(라이브러리별 응답 객체 res.header())를 사용해서 커스텀 응답 헤더를 지정할 수 있습니다.
HINT
@nestjs/common패키지에서Header를 가져옵니다.
응답을 특정 URL로 리다이렉션하려면 @Redirect(url?: string, statusCode?: number) 또는 @Res() → res.redirect()를 직접 호출해야 합니다.
@Get('default')
@Redirect('https://nestjs.com', 301)
@Get('use-res')
redirectToNewRoute(@Res() res: Response) {
return res.redirect('/new-route');
}
@Redirect() 데코레이터는 두개의 인수, url과 statusCode를 선택적으로 받을 수 있습니다. statusCode의 기본값은 생략할 수 경우 302(Found)입니다.
반환된 값은 @Redirect()데코레이터에 전달된 모든 인수를 재정의합니다. 예를 들어:
@Get('docs')
@Redirect('https://docs.nestjs.com', 302)
getDocs(@Query('version') version) {
if (version && version === '5') {
return { url: 'https://docs.nestjs.com/v5/' };
}
}
Nest에서 Route Parameters(라우트 매개변수)는 URL 경로에서 변수를 받아와 동적으로 처리하는 기능입니다. @Param() 데코레이터를 사용하여 요청 경로의 변수를 캡쳐할 수 있습니다. 예를 들어 id와 같은 매개변수는 URL의 일부로 전달되어 핸들러 함수에서 처리할 수 있습니다.
@Get(':id')
getUserById(@Param('id') id: string) {
return `User ID is: ${id}`;
}
이 코드는 /cats/123과 같은 요청을 처리하면, id 값이 함수로 전달됩니다.
→ [라우트 매개변수의 주요 개념]
@Get(':userId/:postId')
getPost(@Param('userId') userId: string, @Param('postId') postId: string) {
return `User ID: ${userId}, Post ID: ${postId}`;
}
위 코드는 GET cats/123/12와 같은 URL에서 두 개의 매개변수를 동적으로 받아서 처리합니다.
→ [라우트 매개변수와 쿼리 매개변수의 차이]
@Params 데코레이터 사용)?key=value 형식으로 전달됩니다. 검색 필터와 같은 정보를 전달할 때 사용할 수 있습니다.(@Query 데코레이터를 사용합니다.)// route parameter example
// client request: GET /usrs/123
@Get('users/:id')
getUserById(@Param('id') id: string) {
return `User ID: ${id}`;
}
// query parameter example
// client requset: GET /users?page-2
@Get('users')
getUserByQuery(@Query('page') page: number) {
return `Page: ${page}`;
}
→ [동적 라우트 매개변수 사용 시 주의 사항]
동적 라우트 경로를 정적 라우트 경로 뒤에 선언해야 하는 규칙이 있습니다. 이유는 매개변수가 있는 경로는 여러 패턴과 일치할 수 있기 때문에, 정적 경로가 먼저 선언되지 않으면 동적 경로가 먼저 처리되어 정적 경로에 해당하는 요청도 동적 경로로 전달될 수 있기 때문입니다.
@Get('profile')
getProfile() {
return 'Profile Page';
}
@Get(':username')
getUserByUsername(@Param('username') username: string) {
return `User: ${username}`;
}
위 예시에서, /profile 과 /john 같은 경로가 있다고 가정하면, 정적 경로(/profile)를 먼저 선언하고 다음에 동적 경로를 선언해야 매개변수화된 경로가 정적 경로의 요청을 가로채지 않습니다.
서브 도메인 라우팅은 특정 서브 도메인을 처리해야 할 경우에 사용됩니다. 예를 들어 서브 도메인을 운영하는 서비스에서 각각의 서브 도메인에 대한 다른 로직을 처리해야 할 때 유용합니다.
Nest에서 서브 도메인 라우팅을 사용하기 위해서는 @Controller 데코레이터에 host 옵션 추가하여 특정 HTTP host와 일치시키도록 할 수 있습니다.
@Controller({ host: 'admin.example.com' })
export class AdminController {
@Get()
index(): string {
return 'Admin page';
}
}
서브 도메인 라우팅에서 동적 값을 처리하는 방법
@Controller()에서 host parameter token을 사용하여 서브 도메인의 동적 값을 캡쳐할 수 있습니다.@HostParam() 데코레이터를 통해 메서드에 접근할 수 있습니다.HINT
host parameter token은 서브 도메인에서 동적 값을 캡쳐하기 위한 방식입니다. 예를 들어, 도메인이{username}.example.com일 경우,{username}이 host parameter token으로 동작하여 사요자 이름을 동적으로 캡쳐할 수 있습니다.
@Controller({ host: ':username.example.com' })
export class UserController {
@Get()
getUser(@HostParam('username') username: string) {
return `Hello, ${username}`;
}
}
Nest에서 Request Payload는 클라이언트가 서버로 보내는 데이터를 의미하며, 주로 POST, PUT, PATCH 요청에서 사용됩니다. 데이터를 처리하기 위해 @Body() 데코레이터를 사용해서 Request Payload를 처리할 수 있습니다. 타입스크립트로 Nest 프로젝트를 구축하는 경우. DTO(Data Transfer Object)를 사용해서 입력 데이터(request payload)의 구조를 명확하게 정의하고, 데이터의 일관성을 유지하고, 유효성 검사를 쉽게 적용할 수 있습니다.
export class CreateDto {
@IsString()
name: string;
@IsNumber()
age: number;
}
@Post()
create(@Body() createDto: CreateDto) {
return this.service.create(createDto);
}
→ [DTO를 클래스로 정의하는 이유]