Validation Pipe를 사용하기 위해서는 몇가지 사전 지식이 필요하다.
1. Data Transfer Object(DTO)
2. class-transformer, class-validator 라이브러리
데이터 전송 객체(DTO)는 클라이언트와 서버 사이에서 전송되는 객체이다.
거창하지만 쉽게 클라이언트에서 작성한 폼을 서버와 주고 받는다면, 폼 그 자체와 폼을 다루는 메서드가 DTO다.
DTO에는 일반적으로 연결된 기능이 없고, 간단한 Class에 property가 나열되었을 뿐인 존재이다.
따라서 클라이언트와 서버가 교환하는 DTO가 어떤 규칙을 갖고 있어야 하는지 명확히 할 필요가 있다.
평범하게 주고받는 일반 JSON 객체 또는 Javascript 객체를 훨씬 더 완전한 기능을 갖춘 class로 변환한다. 클라이언트와 서버가 주고 받는 데이터 뿐만 아니라, 사용되는 메서드 까지도 묶어서 완전한 class로 변환해준다.
dacorator를 사용하여 class로 변환된 DTO가 어떤 data-type인지 유효성 검사를 할 수 있게 만드는 라이브러리이다.
@MaxDate()
@isString()
@Equals
등 다양한 데코레이터를 제공한다.
ValidationPipe는 class-transformer를 자동으로 사용하여 클라이언트 측의 request를 class로 변환하여 가져온 뒤 class-validator 라이브러리를 사용하여 instance들을 validate한다.
1.ValidationPipe를 사용하는 Module에 ValidationPipe 인스턴스 생성
async function bootstrap() {
const app = await NestFactory.create(MessagesModule);
app.useGlobalPipes(
new ValidationPipe()
)
await app.listen(3001);
}
[dtoname].dto.ts
)import {IsString} from 'class-validator';
export class CreateMessageDto {
@IsString()
content: string;
}
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
를 보면
emitDecoratorMetadata
와 experimentalDecorators
옵션이 존재한다.
타입스크립트에서 자바스크립트로 변환 될 때, 타입스크립트는 자바스크립트로 변환되며 모든 스크립트에서 제거되지만 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);