728x90

컨트롤러는 사용자로부터 오는 요청을 받고 다시 응답을 돌려주는 것에 대한 책임이 있다.

 

컨트롤러는 사용자로부터 온 특정한 요청을 어디로 보낼 것인지에 대한 목적으로 만들어졌다. 라우팅 메커니즘은 어떤 컨트롤러가 각각의 요청을 받을 것인지를 결정한다. 종종, 컨트롤러는 여러개의 라우트를 가지며, 그 각각의 라우트는 다른 동작을 수행한다.

 

컨트롤러를 만들기 위해서, 우리는 클래스와 데코레이터를 사용한다. 데코레이터는 해당 클래스의 메타 정보를 통해, Nest가 일치하는 응답을 라우팅 해 줄 수 있도록 도와준다.

 

  • Routing

예시에서 우리는 기본적인 컨트롤러를 만들기 위해 필요한 @Controller() 데코레이터를 사용할 것이다. cats라는 접두사를 가진 경로를 명시하며, @Controller에 접두사를 작성하는 것은 이후에 추가적으로 해당 경로를 더 명시할 필요없이 그룹화 할 수 있도록 도와준다. 예를 들어 우리가 Cats와 상호작용하는 라우트를 만들고 싶다면, 해당 경로의 접두사는 /cats가 될 것이며, @Controller('cats')로 작성하면 이 경로들을 그룹화 해주는 것이다. 그렇기에 컨트롤러에 추가할 라우트들에 'cats를 반복해서 작성 할 필요가 없다.

 

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

@Controller('cats')
export class CatsController {
  @Get()
  findAll(): string {
    return 'This action returns all cats';
  }
}

 

@Get()이라는 Http 요청 데코레이터는 findAll()이라는 메서드 이름 앞에 위치하며, Nest가 특정 경로에 대한 라우트를 생성하도록 한다. 이제 이 route path는 controller에 이미 명시해둔 경로와 메서드에 작성한 데코레이터의 경로를 조합하여 만들어진다. 여기에서는 @Get()에 경로 명시가 없기 때문에 /cats로 들어오는 @Get() 요청에 대해 동작하는 것이다.

 

위의 예시에서 해당 경로로 Get 요청이 들어온다면, Nest는 라우트하여 findAll() 메서드를 호출한다. 여기서 메서드의 이름은 임시이며, Nest는 이 컨트롤러의 메서드 이름에 의미를 부여하지 않는다.

 

해당 메서드는 아마 200 status code를 리턴할 것이다, 저기 작성해둔 문자열과 함께 말이다. 이것에 대해 설명하기 위해서는 2가지의 응답을 바꾸는 방법에 대해 알아야 한다.

 

standard
(recommended)
해당 내장 메서드를 이용하면, Javascript가 객체 혹은 배열을 리턴 할 때, Json으로 자동 변환되어 돌려주게 된다. 하지만 만약 Javascript의 원시타입(string, number..)만 응답한다면, 직렬화를 시도하지 않는다. 
Library-specific 만약 @Res()로 사용하는 response object와 관련된 라이브러리를 사용할 수 있다. 이것을 사용하면, 개발자는 response.status(200).send()과 같이 작성해서 객체를 응답 할 수 있다.

 

  • Request object

핸들러는 종종 클라이언트에서 보낸 요청의 세부 정보를 알아와야 할 때가 있다. Nest는 이런 요청 객체에 대한 접근을 허용한다. 개발자는 @Req() 데코레이터를 사용하여 사용자가 보낸 요청의 객체에 접근이 가능하다.

 

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

@Controller('cats')
export class CatsController {
  @Get()
  findAll(@Req() request: Request): string {
    console.log(request);
    return 'This action returns all cats';
  }
}

 

위와 같은 코드로 request를 출력해보니, 

이런식으로 긴데이터가 들어왔던 것을 볼 수 있었다.

이렇게 많은 데이터에서 원하는 속성을 찾아서 가져오기는 힘들 것 같고, @Body()와 @Query()같은 전용 데코레이터가 있기에 이것들을 사용해서 객체에 접근하게 될 것이다.

 

아래는 각각의 데코레이터들이 어떤것과 대응되는지를 보여주는 표이다.

@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

 

만약 @Res()나 @Response()를 사용하면, Nest에서 해당 핸들러가 응답까지 알아서 처리한다고 생각하고 끝까지 처리해주지 않는다.

그렇기에 해당 데코레이터를 사용하면 응답까지 개발자가 완성해서 리턴해줘야 한다.

 

  • Resources

이전에 cats의 GET API를 만들어보았다. 이번에는 POST를 통해 새로운 핸들러를 만들어보도록 하자.

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';
  }
}

굉장히 간단하며, Nest는 표준의 Http 메서드를 데코레이터를 통해 모두 지원한다.

만약 모든 메서드를 지원하는 엔드포인트를 만들고 싶다면 @All() 데코레이터를 사용하면 된다.

 

  • Route wildcards

패턴을 통해서 라우트하는 기능도 Nest는 지원한다. *을 사용하면 와일드카드로 해당 위치에는 어떤 조합의 경로도 라우트해준다. 

아래의 예시처럼 사용하면 seungkyu/ 뒤의 경로로 어떤 문자열이 오더라도 해당 핸들러로 라우팅해준다.

@Get('abcd/*')
findAll(){
	return 'This route uses a wildcard';
}

 

 

  • Status code

기본적인 응답 코드는 항상 200이고, POST 메서드의 응답코드는 항상 201이다.

이거를 @HttpCode()를 통해 핸들러 레벨에서 쉽게 바꿀 수 있다.

@Post()
@HttpCode(204)
create(){
	return 'This action adds a new cat';
}

 

물론 중간에 에러가 발생하면 바뀌기도 하며, @Res() 혹은 @Response()를 사용해서 직접 넘길 때도 바뀌기도 한다.

 

  • Response headers

response의 header를 직접 명시하기 위해, @Header() 데코레이터를 사용할 수 있다.

물론 res.header()를 통해서 직접 접근도 가능은 하다.

@Post()
@Header('Cache-Control', 'no-store')
create(){
	return 'This action adds a new cat';
}

 

  • Redirection

특정 주소로 리다이렉트 하고 싶다면, @Redirect() 데코레이터에 url과 statusCode를 명시해주면 된다.

만약 statusCode를 명시하지 않는다면, statusCode의 기본값은 302이다.

@Get()
@Redirect('https://nestjs.com', 301)

 

  • Route parameters

정적인 경로만으로 요청하면, 원하는 동적 데이터들을 받을 수 없다.

만약 id와 같은 값을 동적으로 받아오고 싶다면, 파라미터 토큰을 넣어서 가져올 수 있다.

아래 @Get() 데코레이터 예제의 라우트 매개변수 토큰이 바로 그 방식이다.

라우트에 정의한 파리미터는 메서드에 @Param() 데코레이터를 통해 접근 할 수 있다.

@Get(':id')
findOne(@Param() params: any): string{
	console.log(params.id);
    return `This action returns a #${params.id} cat`;
}

 

@Param() 데코레이터는 메서드의 파라미터 데코레이터며, 경로 파라미터에 정의된 값을 메서드가 사용 할 수 있도록 해준다.

위에서는 id에 접근하기 위해 params.id를 사용했지만, 라우트 파라미터의 이름에 직접 접근하여 바로 값을 가져올 수도 있다.

 

@Get(':id')
findOne(@Param('id') id: string): string{
	return `This action returns a #${id} cat`;
}

 

  • Sub-domain routing

@Controller() 데코레이터는 host 옵션을 받을 수 있다.

host 옵션은 해당 주소에서 온 HTTP 요청만 처리하겠다는 의미이다.

@Controller({host: 'admin.example.com'})
export class AdminController{
	@Get()
    index(): string {
    	return 'Admin page';
    }
}

 

여기서도 주소에서 동적인 값을 찾아서 올 수 있다.

host에서 선언된 매개변수는 @HostParam() 데코레이터를 추가해서 접근 가능합니다.

@Controller({host: ':account.example.com'})
export class AccountController{
	@Get()
   	getInfo(@HostParam('account') account: string) {
    	return account;
    }
}

 

  • Asynchronicity

자바스크립트의 기능을 최대한 활용하기 위해, 비동기 데이터 핸들링을 사용한다.

모든 async 함수들은 해당 데이터를 다루며 자동으로 값을 반환하는 Promise 타입을 반환한다.

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

 

해당 코드도 충분히 멋지지만, Nest는 RxJs를 통한 observable stream도 지원한다.

Nest가 해당 데이터를 구독하며, 내부적으로 알아서 값을 반환하게 된다.

@Get()
findAll(): Observable<any[]>{
	return of([]);
}

 

  • Request payloads

이전에서 했던 POST는 사용자가 보내는 파라미터들을 받지 않았었다.

그것을 @Body()로 해결해보자.

 

우선 사용하기 전에 DTO를 정의해보자.

DTO는 네트워크를 통해 데이터를 전송할 때, 어떻게 보내야할지 명시하는 객체이다.

Nest에서는 인터페이스 혹은 클래스를 사용해 DTO 스키마를 정의한다.

하지만 이 중에서도 class로 정의하는 것을 추천한다.

클래스는 ES6 자바스크립트 문법이기에 javascript 자체로 컴파일이 가능하다.

그에 비해, 인터페이스는 변환 과정에서 삭제되기 때문에 Nest는 런타임 중에 해당 인터페이스를 참조 할 수 없다.

이것은 파이프같은 기능들이 런타임 중 변수의 타입에 접근해야 하기에 중요하다.

 

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

 

이제 CatsController에 넣어보자.

 

import { Body, Controller, Get, Post } from '@nestjs/common';
import { CreateCatDto } from './dto/create-cat.dto';

@Controller('cats')
export class CatsController {
  @Get()
  findAll(): string {
    return 'This action returns all cats';
  }
  @Post()
  create(@Body() createCatDto: CreateCatDto): string {
    console.log(createCatDto);
    return 'This action adds a new cat';
  }
}

 

이렇게 @Body() 데코레이터를 통해, POST에서 사용자가 보낸 데이터를 사용할 수 있다.

 

  • Query parameters

@Query()를 사용해 요청에서 들어온 쿼리 파라미터를 가져올 수 있다.

  @Get()
  findAll(@Query() age: number, @Query() breed: string): string {
    return `This action returns all cats filtered by age: ${age} and breed: ${breed}`;
  }

 

이런 핸들러에 다음과 같은 요청을 보내면

http://localhost:3000/cats?age=2&breed=thief

 

이렇게 응답이 오는 것을 볼 수 있다.

 

  • Getting up and running

CatsController를 완벽하게 다 작성했어도, 동작이 바로 되는 것은 아니다.

컨트롤러는 모듈의 일부이며, 우리는 @Module 데코레이터에 이 컨트롤러를 넣어줘야 한다.

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

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

'Node > Nest 공식문서' 카테고리의 다른 글

Modules  (0) 2025.08.23
Providers  (0) 2025.08.21
First steps  (2) 2025.08.18
Introduction  (4) 2025.08.18

+ Recent posts