본문 바로가기
nestJS

NestJS | Class Validator, Transformer

by 리잼 2024. 11. 20.
반응형

Class Validator

Class Validator는 NestJS에서 데이터 유효성 검사를 수행하기 위해 사용하는 유효성 검사 라이브러리

DTO(Data Transfer Object)와 함께 사용되어, 데이터의 구조와 유효성을 정의하고, 요청 데이터를 자동으로 검증한다.

 

  • 데코레이터 기반 검증
    • 검증 규칙을 정의하는 데 데코레이터를 사용함
    • 필드 수준에서 적용하며, 다양한 유효성 검사 규칙을 제공
  • DTO와 함께 사용
    • 클라이언트 요청 데이터를 특정 DTO 클래스로 매핑하여 검증
  • NestJS의 파이프와 연동
    • ValidationPipe 를 사용하면 요청 시 데이터 검증이 자동으로 수행된다

설치 방법

 

npm install class-validator

주요 데코레이터

Decorator 설명
@IsString() 문자열인지 확인
@IsInt() 정수인지 확인
@IsEmail() 유효한 이메일 형식인지 확인
@IsOptional() 해당 필드가 선택적인지 확인
@Min(value) 숫자 값이 최소값 이상인지 확인
@Max(value) 숫자 값이 최대값 이하인지 확인
@Length(min, max) 문자열 길이가 최소, 최대값 범위 내에 있는지 확인
@Matches(regex) 주어진 정규식과 일치하는지 확인
@IsEnum(enum) 값이 특정 열거형(Enum) 값 중 하나인지 확인
@IsArray() 배열인지 확인
@ArrayMinSize(size) 배열의 최소 길이를 검증

 

ValidationPipe 설정

  • ValidationPipe를 글로벌 또는 특정 경로에서 설정하면, DTO를 자동으로 검증

main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // 글로벌 ValidationPipe 설정
  app.useGlobalPipes(new ValidationPipe());

  await app.listen(3000);
}
bootstrap();

 

create-post.dto.ts

import { IsString } from 'class-validator';

export class CreatePostDto {
  @IsString() // 해당 속성이 문자열인지 확인하는 데코레이터
  title: string;
  @IsString()
  content: string;
}

post.service.ts / DTO 적용 전, 후
post.controller.ts / DTO 적용 전, 후

DTO 를 이용해서 간결한 코드를 만들 수 있다.

 

PickType 활용

Typescript 에서 제공하는 유틸리티인 Pick 을 이용하면 DTO 를 모델에 상속을 시킬 수 있다.

하지만 그냥 Pick을 사용하면 타입을 반환하기 때문에 값이 필요한 DTO에서 상속이 불가능하다.

Pick vs PickType

기능 Pick PiccType
목적 인터페이스 또는 타입에서 속성을 선택 클래스에서 속성을 선택
사용 환경 타입스크립트 일반적인 타입 시스템 NestJS의 DTO 또는 클래스 기반 설계
리플렉션 메타데이터 지원하지 않음 지원 (Swagger와 같은 NestJS 툴에서 활용 가능)
사용 예시 Pick<Type, Keys> PickType(Class, Keys as const)
import { IsOptional, IsString } from 'class-validator';
import { PostsModel } from '../entity/post.entity';
import { PickType } from '@nestjs/mapped-types';

export class CreatePostDto extends PickType(PostsModel, ['title', 'content']) {}
  • 위와 같이 PickType을 이용해서 extends 를 해야한다.

Class Transformer

Class Transformer는 객체를 변환하거나, 직렬화 및 역직렬화를 통해 플레인 자바스크립트 객체(Plain Object)와

클래스 인스턴스 간의 변환을 쉽게 수행하도록 도와주는 도구이다.

이는 주로 데이터를 정리하거나, 유효성 검사와 직렬화를 위해 사용된다

npm install class-transformer

주요 데코레이터

  1. @Expose / @Exclude
    • 직렬화 시 포함하거나 제외할 프로퍼티를 정의함
  2. @Transform
    • 특정 프로퍼티를 변환하기 위한 로직을 정의함
  3. @Type
    • 프로퍼티가 클래스 타입인 경우 타입을 지정해 변환을 도와줌

장점

  • 데이터 정제: API 요청/응답 데이터 정제 및 변환을 쉽게 처리.
  • 유효성 검사와 결합: class-validator와의 조합으로 안전한 데이터 처리가 가능.
  • 직렬화 최적화: 불필요한 데이터를 자동으로 제외하거나 필요한 형태로 가공.

@Exclude 사용예시 : 비밀번호 정보 포함된 데이터 문제

  1. getUser() 함수의 역할
    • getUser() 함수는 데이터베이스에서 유저 정보를 조회하여 반환한다.
      이때 반환되는 객체에는 모든 유저 정보(예: 이름, 이메일, 비밀번호 등)가 포함되고 있다.
  2. 비밀번호 포함 문제
    • API 응답으로 비밀번호가 포함된 데이터가 클라이언트에 전달된다면, 이는 보안상 심각한 문제가 된다.
      비밀번호와 같은 민감한 정보는 절대 사용자에게 노출되어서는 안됨
  3. select 옵션으로 비밀번호 제외
    • @Column({ select: false }) 옵션을 사용해 특정 필드를 기본적으로 쿼리 결과에 포함하지 않도록 설정할 수 있지만
      이는 전역적으로 적용되므로, 다른 비즈니스 로직에서 비밀번호가 필요한 경우에도
      select: false로 인해 해당 필드를 사용할 수 없게 되는 단점이 있다.
  4. @Exclude로 문제 해결
    • @Exclude는 직렬화 단계에서만 동작하기 때문에, 데이터베이스에서 필요한 모든 정보를 가져오되,
      클라이언트에 데이터를 반환할 때 민감한 정보를 제외하는 방식으로 문제를 해결할 수 있다.

user.entity.ts

user.controller.ts

import { Body, ClassSerializerInterceptor, Controller, Get, Post, UseInterceptors } from '@nestjs/common';
import { UsersService } from './users.service';

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

  @Get()
  @UseInterceptors(ClassSerializerInterceptor)
  /*
  serialization -> 직렬화 -> 현재 시스템에서 사용되는 데이터의 구조를 다른 시스템에서도
                            쉽게 사용할 수 있는 포맷으로 변환
                            -> class object에서 JSON으로 변환
  deserialization -> 역직렬화
   */
  getAllUsers() {
    return this.usersService.getAllUsers();
  }
}

Exclude() 적용 전, 후

 

@Expose() 예시

user.entity.ts

  @Expose()
  get nicknameAndEmail() {
    return this.nickname + '/' + this.email;
  }

Expose()를 이용하면 존재하지 않은 프로퍼티를 Export 할 수 있다.

 

Expose()를 클래스에도 적용할 수 있다.

@Entity()
@Exclude()
export class UsersModel extends BaseModel {
	...	// 코드 생략
  @Column({
    length: 20,
    unique: true,
  })
  @Expose()
  nickname: string;
}

getUser() 호출 결과

  • 자체 클래스에 Exclude()를 하고 보여주고 싶은 프로퍼티에 Expose() 하게 되면 원하는 프로퍼티만 출력이 가능하다.

 

반응형

'nestJS' 카테고리의 다른 글

NestJS | Multer, Static File Serving  (0) 2024.11.26
NestJS | Guard  (0) 2024.11.20
NestJS | Pipe  (0) 2024.11.20
NestJS | TypeORM Table Inheritance  (0) 2024.11.12
NestJS | TypeORM Entity Embedding  (2) 2024.11.12