[nestjs] Controllers

Creating the dots·2022년 5월 12일
0

nestjs

nestjs 공식문서를 부분적으로 정리한 내용입니다.


controllers

controller는 요청을 받고 그에 따른 응답을 클라이언트에게 넘겨주는 역할을 한다.

routing은 특정 controller가 특정 요청을 받도록 제어하는 역할을 한다. 대체로 각 controller는 하나 이상의 라우트를 가지며, 다른 라우트들은 다른 액션을 수행한다.

기본적인 controller를 만들기 위해 클래스와 데코레이터를 사용한다. 데코레이터는 클래스와 필요한 메타데이터를 연관짓고(associate) 네스트가 라우팅 맵을 만들수 있도록 한다. (tie requests to the corresponding controllers)

routing

다음 예시에서는 기본적인 컨트롤러 정의에 필요한 @Controller 데코레이터를 사용한다. 옵셔널 라우트 패스의 접두어로 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
    Nest가 요청에 대한 특정 엔드포인트를 만들 수 있도록 한다. 이 경우 GET /cats로 요청을 보낼 수 있게 된다. 여기서 cats로 생성된 것은 우리가 파일명을 cats.controller.ts로 생성했기 때문이며 @Get의 인자로 어떠한 것도 작성해주지 않았기 때문이다. 만약, @Get('profile')로 작성되었다면 GET /cats/profile이 될 것이다.

  • findAll

    • GET /cats로 요청이 왔다면, 네스트는 요청을 findAll로 라우팅한다. 이 메소드 이름은 임의로 설정된 것이며 변경가능하다.
    • 이 메소드는 200 상태코드와 관련된 응답을 리턴하며, 이 예시에서는 문자열을 리턴한다.
    • 네스트가 응답을 보내는 두가지 방식이 있는데, 자세한 내용은 공식문서를 참고하자

Request object

네스트는 @Req() 데코레이터를 핸들러의 시그니처(signature)에 작성하도록 함으로써 요청 객체 (request object)에 접근할 수 있도록 한다.

  • 아래의 예시 코드에서는 express로부터 Request 객체를 import해오는데, 네스트에서 디폴트로 사용하는 플랫폼은 Express이며, 다른 플랫폼으로는 fastify 등이 있다.
  • 만약 에러가 발생한다면, npm i -D @types/express로 패키지를 설치한다.
  • 여기서 요청 객체에는 요청 쿼리스트링, 파라미터, 헤더, 바디 등의 속성이 포함되어있다. 대부분의 경우에는 이러한 속성들을 각각 꺼내서 사용하지 않고, 지정된 데코레이터를 대신 사용하는데, 예를 들면 @Body(), @Query() 등이 있다.
    • 자세한 데코레이터에 대한 설명은 공식문서를 참고하자
  • 네스트는 @Res 데코레이터도 제공하는데, 네이티브 플랫폼의 응답 객체 인터페이스로, 이를 사용할 경우 메소드 핸들러에 @Res()를 작성해주어야 한다. 이렇게 직접 작성해주는 경우, 위에서 언급한 네스트가 응답을 보내는 두가지 방식 중 Library-specific mode에 해당된다. 따라서, 직접 res.json() 또는 res.send()의 형태로 응답을 보내주어야한다.
//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';
  }
}

Resources

네스트는 모든 HTTP 메소드에 대한 데코레이터를 제공한다.
@Get(), @Post(), @Put(), @Delete(), @Patch(), @Options(), @Head(), and @All

  • @Post
    앞서서 고양이 리소스 데이터를 fetch해오는 엔드포인트를 작성했다면, 새로운 레코드를 생성하는 엔드포인트를 만들 수 있다. 이는 다음의 예시처럼 @Post를 사용한다.
import { Controller, Get, Post, Req } from '@nestjs/common';
import { Request } from 'express';

@Controller('cats')
export class CatsController {
  @Post() //추가
  create(): string {
    return 'This action adds a new cat';
  } //추가

  @Get()
  findAll(@Req() request: Request): string {
    return 'This action returns all cats';
  }
}

Route wildcards

  • 다음 예시에는 아스트리크가 와일드카드로 사용되었는데, abcd, ab_cd, abecd 등의 경우가 매칭된다. 아스트리크 외에도 ?, +, *, () 등이 사용될 수 있다.
@Get('ab*cd')
findAll() {
  return 'This route uses a wildcard';
}

status code

  • 상태코드는 디폴트로 200이 전달되며 (post의 경우 201) @HttpCode 데코레이터를 사용해 변경할 수 있다.
    • import { HttpCode } from @nestjs/common
@Post()
@HttpCode(204)
create() {
  return 'This action adds a new cat';
}

Headers

  • 커스텀 헤더를 정의할때에는 @Header 데코레이터를 사용하거나 특정 라이브러리에 해당되는 응답 객체를 사용할 수 있다. (req.header())
    • import { Header } from @nestjs/common
@Post()
@Header('Cache-Control', 'none')
create() {
  return 'This action adds a new cat';
}

Redirection

  • 특정 URL로 리다이렉트 시킬때에는 @Redirect() 데코레이터 또는 res.redirect()와 같은 특정 응답 객체를 사용할 수 있다.
  • @Redirect(url, statusCode)의 형태이며 두 개의 인자 모두 옵셔널하다. 상태코드의 디폴트 값은 302이다.
  • 만약 동적으로 url 등을 변경하고 싶다면, url과 status를 값으로 가지는 객체를 리턴시키면 된다. 리턴된 객체의 값이 @Redirect() 데코레이터에 전달된 값을 덮어씌운다.
@Get()
@Redirect('https://nestjs.com', 301)

//동적으로 변경하고 싶은 경우
@Get('docs')
@Redirect('https://docs.nestjs.com', 302)
getDocs(@Query('version') version) {
  if (version && version === '5') {
    return { url: 'https://docs.nestjs.com/v5/' };
  }
}

Route parameters

  • 요청 URL에 포함되어있는 파라미터 정보는 @Get() 데코레이터에 다음과 같이 파라미터 토큰을 작성하여 꺼내올 수 있다. 여기서는 특정 id의 고양이 데이터를 조회하는 것이므로 메소드 이름이 findOne인 것도 확인하 수 있다.
  • 두번째 예시와 같이 파라미터의 특정 값을 꺼내올 수 있다.
 @Get(':id')
  findOne(@Param() params): string {
    console.log(params.id);
    return `This action returns a #${params.id} cat`;
  }

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

Asynchronicity

  • 자바스크립트는 데이터를 비동기 방식으로 추출한다. 따라서 네스트도 async 함수를 지원한다.
  • 모든 async 함수는 프로미스를 리턴한다. 즉 네스트가 resolve할 수 있는 연기된/미뤄진 값(deferred value)를 리턴할 수 있다는 것을 의미한다.
  • 아래 두가지 경우 모두 사용가능하며 필요에 따라 선택해서 사용하면 된다. 두번째 예시는 조금 더 강력한 기능을 제공하는데, 네스트의 라우트 핸들러는 RxJS ovservable streams를 리턴할 수 있다.
    • RxJS observable streams에 대해서는 추가적인 공부가 필요할 것 같다.
@Get()
async findAll(): Promise<any[]> {
  return [];
}

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

Request payloads

  • 타입스크립트를 사용한다면, DTO(Data Transfer Object) 스키마를 정해야한다. DTO란, 네트워크를 통해 전달되는 데이터 형태를 정의한 객체이다. 이는 타입스크립트의 interface, class 등으로 정의할 수 있다.
    • 네스트에서 추천하는 방법은 클래스를 활용한 것이다. 그 이유는, 클래스는 자바스크립트 ES6 문법의 일부이므로, 자바스크립트로 컴파일 되었을때에도 사용가능하다. (인터페이스는 자바스크립트로 컴파일되지 않음)
  • ValidationPipe가 메소드 핸들러에게 전달되지 않아야할 속성들을 필터링할 수 있는데, 이 경우에는 acceptable한 속성들만 화이트리스트로 만들 수 있다. 화이트리스트에 포함되지 않은 속성들은 자동으로 객체에서 제거된다.
//create-cat.dto.ts
export class CreateCatDTO {
  name: string;
  age: number;
  breed: string;
}

//cats.controller.ts
@Post()
async create(@Body() createCatDto: CreateCatDto) {
  return 'This action adds a new cat';
}
profile
어제보다 나은 오늘을 만드는 중

0개의 댓글