Skip to main content

Command Palette

Search for a command to run...

[ 살펴보기 ] NestJS - Controller

Updated
3 min readView as Markdown
[ 살펴보기 ] NestJS - Controller
C

A developer living in Busan, Korea

NestJS Controller는 client의 요청을 전달 받고 그에 따른 response를 전달해주는 역할을 한다. 그리고 각 controller은 route 역할을 하며 client의 요청을 분류한다

다음 예제를 살펴보자

import {
  Controller,
  Get,
  Post,
  Body,
  Patch,
  Param,
  Delete,
} from '@nestjs/common';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';

@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Post()
  create(@Body() createUserDto: CreateUserDto) {
    return this.usersService.create(createUserDto);
  }

  @Get()
  findAll() {
    return this.usersService.findAll();
  }

  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.usersService.findOne(id);
  }

  @Patch(':id')
  update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
    return this.usersService.update(id, updateUserDto);
  }

  @Delete(':id')
  remove(@Param('id') id: string) {
    return this.usersService.remove(id);
  }
}

위의 코드는 nest g resource users 명령을 통해 생성한 users controller 파일이다. ( nest g resource를 통해 생성하면 controller, service, entity, dto 코드를 모두 자동으로 생성해준다 )

만약 서버가 localhost:4000에서 구동되고 있다면 client는 localhost:4000/users url을 통해 요청을 보내면 해당 controller에서 해당 요청을 처리한다. @Controller decorator가 users라는 string값을 받고 있기에 users라는 텍스트가 라우팅 경로 사용된다.

Client의 요청의 method 종류나 path param 여부에 따라 controller에서 어떤 method가 사용되는지 달라진다. 다음 예를 살펴보자

method가 post고 url이 localhost:4000/users인 요청은 create함수에서 처리된다

  @Post()
  create(@Body() createUserDto: CreateUserDto) {
    return this.usersService.create(createUserDto);
  }

method가 get이고 url이 localhost:4000/users인 요청은findAll 함수에서 처리된다

  @Get()
  findAll() {
    return this.usersService.findAll();
  }

method가 get이고 url이 localhost:4000/users/123과 같이 /users 이후 path param이 추가되면 요청이 findOne함수에서 처리된다

  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.usersService.findOne(+id);
  }

method가 patch이고 url이 localhost:4000/users/123과 같이 /users 이후 path param이 추가되면 요청이 update 함수에서 처리된다

  @Patch(':id')
  update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
    return this.usersService.update(+id, updateUserDto);
  }

method가 delete이고 url이 localhost:4000/users/123과 같이 /users 이후 path param이 추가되면 요청이 remove함수에서 처리된다

  @Delete(':id')
  remove(@Param('id') id: string) {
    return this.usersService.remove(+id);
  }

위의 예제에서 볼 수 있듯이 controller의 어떤 함수가 요청을 처리할 지는 client의 request url과 method에 따라 달라진다

Controller에서 요청 객체 접근

NestJS는 default로 express 기반으로 동작하기에 요청 객체에 타입 역시 express package로부터 import한다. 그리고 @Req decorator를 통해 요청 객체 접근할 수 있다

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

@Get()
findAll(@Req() req: Request) {
  console.log(req)
  ...
}

요청 객체가 아닌 query, param 또는 body와 같이 request 객체에서 필요한 부분만 사용할 수 있도록 NestJS는 @Query, @Param, @Body decorator를 제공한다

Controller 응답 조정하기

NextJS에선 default로 POST method에 대한 성공 응답 코드는 201 그리고 나머지 method에 대한 성공 응답 코드는 200을 반환한다.

만약에 응답 코드를 변경하고자 한다면 다음과 같이 HttpCode decorator를 사용할 수 있다

import {
  ...
  HttpCode,
} from '@nestjs/common';

@HttpCode(202)
@Get()
findAll(@Req() req: Request) {
  ...
}

만약 응답에 특정 header값을 추가해야 한다면 @Headerdecorator를 통해 추가할 수 있다

  import {
  ...
  Header,
  HttpCode,
} from '@nestjs/common';

@HttpCode(202)
@Get()
findAll(@Req() req: Request) {
    ...
}

요청에 실려오는 path param은 @Param decorator를 통해 주입받는다

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

@Patch(':id')
update(@Param('id') id: string) {
    ...
}

위의 예제를 기준으로 만약에 요청 url이 /users/123과 같은 url로 들어온다면 123 부분이 바로 path param이다.

만약 /users/123/order/123과 같이 path param을 복수로 받을 때는 다음과 같이 처리할 수 있다

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

@Patch(':id/order/:orderId')
update(
    @Param('id') id: string, 
    @Param('orderId') orderId:string
) {
    ...
}

Request Body 다루기

NestJS에서 Request Body를 DTO로 선언하여 관리한다. 다음 예제를 살펴보자. 만약 새로운 user를 생성하는데 email과 name 두 필드를 받는다고 가정해보자. 우선 body에 대한 dto를 생성한다

export class CreateUserDto {
  email: string;
  name: string;
}

그리고 생성한 dto를 controller user 생성을 처리하는 method에 적용하여 사용할 수 있다

import { CreateUserDto } from './dto/create-user.dto';

@Post()
create(@Body() createUserDto: CreateUserDto) {
  console.log(createUserDto)
  ...
}

만약 GET method 요청에서 pagination 관련 요청시 query param을 처리할 때도 DTO를 선언하여 처리할 수 있다. 먼저 query param에 대한 DTO를 생성한다.

export class GetUserDto {
  page: string;
  limit: string;
}

그리고 생성한 DTO를 다음과 같이 적용해준다

import { GetUserDto } from './dto/get-user.dto';

@Get()
findAll(@Query() query: GetUserDto) {
    console.log(query);
    ...
}

이제 /users?limit=10&page=2와 같은 요청이 들어왔을 때 함께 전달된 query param에 접근할 수 있다

More from this blog

[ 살펴보기 ] TypeORM - Transactions, Migration

Transation Database 종류에 따라 detail한 부분은 차이점이 조금씩 있겠지만 각 sql statement는 개별적인 transaction block을 통해 실행되며 Database 설정에 따라 sql statement의 실행 결과가 자동으로 commit되어 영구히 적용되거나 commit을 직접 실행하기 전까지는 영구히 적용되지 않을 수 있다. 대부분의 경우 default로 sql statement 실행 결과가 자동으로 comm...

Feb 9, 20256 min read
[ 살펴보기 ] TypeORM - Transactions, Migration

Dev Diary

184 posts