nestjs) ValidationPipe + Decorator

김명성·2022년 11월 12일
0
post-custom-banner

Validation Pipe를 사용하기 위해서는 몇가지 사전 지식이 필요하다.
1. Data Transfer Object(DTO)
2. class-transformer, class-validator 라이브러리

Data Transfer Object (DTO)

데이터 전송 객체(DTO)는 클라이언트와 서버 사이에서 전송되는 객체이다.
거창하지만 쉽게 클라이언트에서 작성한 폼을 서버와 주고 받는다면, 폼 그 자체와 폼을 다루는 메서드가 DTO다.

DTO에는 일반적으로 연결된 기능이 없고, 간단한 Class에 property가 나열되었을 뿐인 존재이다.

따라서 클라이언트와 서버가 교환하는 DTO가 어떤 규칙을 갖고 있어야 하는지 명확히 할 필요가 있다.

class-transformer

평범하게 주고받는 일반 JSON 객체 또는 Javascript 객체를 훨씬 더 완전한 기능을 갖춘 class로 변환한다. 클라이언트와 서버가 주고 받는 데이터 뿐만 아니라, 사용되는 메서드 까지도 묶어서 완전한 class로 변환해준다.

class-validation

dacorator를 사용하여 class로 변환된 DTO가 어떤 data-type인지 유효성 검사를 할 수 있게 만드는 라이브러리이다.

@MaxDate() @isString() @Equals 등 다양한 데코레이터를 제공한다.


ValidationPipe

ValidationPipe는 class-transformer를 자동으로 사용하여 클라이언트 측의 request를 class로 변환하여 가져온 뒤 class-validator 라이브러리를 사용하여 instance들을 validate한다.


use-case

1.ValidationPipe를 사용하는 Module에 ValidationPipe 인스턴스 생성

async function bootstrap() {
  const app = await NestFactory.create(MessagesModule);
  app.useGlobalPipes(
    new ValidationPipe()
  )
  await app.listen(3001);
}
  1. DTO 설정 (별도 파일로 관리 [dtoname].dto.ts)
import {IsString} from 'class-validator';

export class CreateMessageDto {
  @IsString()
  content: string;
}
  1. Controller에 작성한 DTO 적용
import { Controller, Get, Post,Body,Param } from '@nestjs/common';
import { CreateMessageDto } from './dtos/create-message.dto';

@Controller('messages')
export class MessagesController {

  @Post()
  createMessage(@Body() body: CreateMessageDto) {
    console.log(body);
  }  
}

DTO 규칙에 맞지 않는다면 오른쪽과 같은 Error를 response한다.


여기서 타입스크립트는 런타임 이전에 자바스크립트로 변환되는데 어떻게 실제 런타임에 유효성 검사를 하여 error message를 반환할 수 있는지, 즉 타입스크립트로 작성한 정보를 런타임에 어떻게 보존할 수 있는지 궁금할 수 있다.

이 마법같은 동작 방법은 tsconfig.json에 담겨있으며, 이 부분이 nestjs의 핵심이다.

tsconfig.json의 compilerOptions를 보면
emitDecoratorMetadataexperimentalDecorators 옵션이 존재한다.

emitDecoratorMetadata

타입스크립트에서 자바스크립트로 변환 될 때, 타입스크립트는 자바스크립트로 변환되며 모든 스크립트에서 제거되지만 tsconfig.js의 emitdecoratorMetadata옵션이 true라면, metadata로 Decorator가 동작하게 할 수 있다.

메타데이터 ?
메타데이터는 데이터에 대한 데이터로서 해당 데이터에 대한 설명을 해 주는 데이터이다.
예를들면 http request를 보내는 상황에서 작성한 데이터가 {"email":"forwarm5891@gmail.com"}이라면,
이 데이터의 타입을 알려주는 'content-type':application/json이
{"email":"forwarm5891@gmail.com"}의 메타데이터가 된다.

즉 타입스크립트의 Decorator의 기능을 자바스크립트에서 동작할 수 있게끔 코드가 생성되어 런타임에도 해당 Decorator의 규칙이 지속된다.

아래는 decorator를 통해 작성된 타입스크립트 파일과 자바스크립트로 변환된 decorator code이다.


typescript

  @Post()
  createMessage(@Body() body: CreateMessageDto) {
    //...
  }

javascript

__decorate([
    (0, common_1.Post)(),
  	// createMessage 메소드의 첫번째 인수에 추가된 Decorator
    __param(0, (0, common_1.Body)()),
    __metadata("design:type", Function),
  // javascript가 type-innotation을 알게 만들어 주는 design:paramtypes
  // ValidationPipe를 통해 들어오는 request에 대해 해당 속성을 조회한다.
    __metadata("design:paramtypes", [create_message_dto_1.CreateMessageDto]),
    __metadata("design:returntype", void 0)
], MessagesController.prototype, "createMessage", null);
post-custom-banner

0개의 댓글