낙서장이자 오답 노트이자 컨닝 페이퍼

패스트캠퍼스 환급챌린지 6일차 : 코드팩토리의 백엔드 아카데미 : 한 번에 끝내는 NestJS 패키지 - 기초부터 MSA까지 강의 후기 본문

NestJS

패스트캠퍼스 환급챌린지 6일차 : 코드팩토리의 백엔드 아카데미 : 한 번에 끝내는 NestJS 패키지 - 기초부터 MSA까지 강의 후기

NangIn 2025. 4. 6. 20:49

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성하였습니다.

 

강의 내용 정리   

 

dto 소개 및 사용해보기

 

DTO (Data Transfer Object)란?

  • Controller에서 Body 데이터를 구조화하여 받기 위한 클래스
  • 매번 @Body('title'), @Body('genre')처럼 받지 않고,
  • 하나의 클래스로 타입 정의 후 통째로 받음

 

왜 DTO를 써야 하나?

  1. 코드 재사용
    • 같은 구조의 요청이 여러 곳에 필요할 경우 DTO 클래스를 재활용 가능
  2. 유지보수 편의
    • 필드가 추가되거나 바뀌어도 DTO만 수정하면 반영됨
  3. 가독성 향상
    • controller에서 인자 나열 없이 .title, .genre로 바로 접근 가능

 

DTO 파일 생성 흐름

  • createMovie.dto.ts
export class CreateMovieDto {
  title: string;
  genre: string;
}
  • updateMovie.dto.ts
    • update는 일부만 수정하므로 optional(?) 처리
export class UpdateMovieDto {
  title?: string;
  genre?: string;
}

 

서비스 메서드에 DTO 적용

// Before
createMovie(title: string, genre: string) { ... }

// After
createMovie(dto: CreateMovieDto) {
  const movie = { ...dto, id: this.idCounter++ };
  ...
}
updateMovie(id: number, dto: UpdateMovieDto) {
  const movie = this.findMovie(id);
  Object.assign(movie, dto);
  ...
}

 

컨트롤러에 DTO 적용

@Post()
create(@Body() body: CreateMovieDto) {
  return this.movieService.createMovie(body);
}

@Patch(':id')
update(@Param('id') id: string, @Body() body: UpdateMovieDto) {
  return this.movieService.updateMovie(+id, body);
}

 

결과적으로 얻는 장점

  • 인자 수 줄어들고, 스프레드 연산자로 유연하게 처리
  • 바디 데이터에 대한 정의/검증의 기반을 마련
  • class-validator와 함께 쓰면 유효성 검사도 가능해짐

 

Class Validator 소개

 

왜 Class Validator가 필요한가?

  • NestJS에서 API를 만들 때, 타입만 선언해도 자동으로 유효성 검사가 될 거라 착각하기 쉬움
  • 하지만 실제로는 title, genre와 같은 필드를 비워서 요청해도 정상 응답됨 → 이는 타입스크립트 타입만으로는 런타임 유효성 검사가 안 되기 때문임
  • → 그래서 클래스 밸리데이터(Class-validator)가 필요함

 

Class-validator란?

  • 타입스크립트 데코레이터를 활용해 클래스 속성에 유효성 규칙을 선언 (Validate)
  • 비동기 및 동기 방식 모두 지원
  • 기본 제공되는 Validator가 다양 (예: @IsNotEmpty, @IsEmail, @IsOptional)
  • 커스텀 Validator& 에러 메시지도 가능

 

어떻게 사용하나?

  • DTO 클래스에서 각 필드 위에 데코레이터 선언
import { IsNotEmpty, IsEmail } from 'class-validator';

export class CreateUserDto {
  @IsNotEmpty({ message: '이름을 입력해 주세요.' })
  name: string;

  @IsEmail({}, { message: '정확한 이메일 주소를 입력해 주세요.' })
  email: string;
}

 

기본 제공 Class Validator구분 Validator 종류

공통 Validator @IsDefined, @IsOptional, @Equals, @NotEquals, @IsEmpty, @IsNotEmpty, @IsIn, @IsNotIn
타입 Validator @IsBoolean, @IsDate, @IsString, @IsNumber, @IsInt, @IsArray, @IsEnum
숫자 Validator @IsDivisibleBy, @IsPositive, @IsNegative, @Min, @Max
문자 Validator @Contains, @NotContains, @IsAlphanumeric, @IsCreditCard, @IsHexColor, @MaxLength, @MinLength, @IsUUID, @IsLatLng

 

검증 실패 시 반환 에러 구조

{
  target: Object;
  property: string;
  value: any;
  constraints?: {
    [type: string]: string;
  };
  children?: ValidationError[];
}
  • target: 검증한 전체 객체
  • property: 검증 실패한 프로퍼티
  • value: 검증 실패한 값
  • constraints: 검증 실패한 제약 조건 (isNotEmpty, isEmail 등)
  • children: 프로퍼티의 모든 검증 실패 제약 조건

 

커스텀 에러 메세지

class User {
  @IsNotEmpty({
    message: '이름을 입력해주세요!'
  })
  name: string;

  @IsEmail({}, {
    message: '정확한 주소를 입력해주세요!'
  })
  email: string;
}
  • Decorator의 message 프로퍼티에 검증 실패했을 때의 에러 메세지를 입력해주면 된다.

 

핵심 요약

  • 타입만 선언한다고 런타임 유효성 검사가 되는 게 아님
  • class-validator를 통해 요청 데이터의 유효성 보장
  • 데코레이터 기반 선언식 문법으로 가독성 및 재사용성 향상
  • NestJS + DTO + class-validator 조합 → 견고한 API 구성 가능

 

Class Validator 프로젝트에 적용하기

 

설치 및 환경 설정

pnpm add class-validator class-transformer
  • class-validator: 유효성 검사 라이브러리
  • class-transformer: 이후 DTO 변환 시 함께 사용됨
  • main.ts 설정:
import { ValidationPipe } from '@nestjs/common';

app.useGlobalPipes(new ValidationPipe());
  • ValidationPipe를 전역에 등록해야 DTO 유효성 검사가 동작함

 

DTO에 유효성 검사 데코레이터 추가

  • 예시: create-movie.dto.ts
import { IsNotEmpty } from 'class-validator';

export class CreateMovieDto {
  @IsNotEmpty()
  title: string;

  @IsNotEmpty()
  genre: string;
}
  • @IsNotEmpty() → 해당 필드는 빈 값이면 안 됨

 

Controller에 DTO 적용

@Post()
create(@Body() body: CreateMovieDto) {
  return this.movieService.create(body);
}
  • 바디를 DTO 클래스로 받으면, 유효성 검사가 자동으로 실행됨

 

PATCH처럼 선택적 필드 처리

  • 예시: update-movie.dto.ts
import { IsOptional, IsNotEmpty } from 'class-validator';

export class UpdateMovieDto {
  @IsOptional()
  @IsNotEmpty()
  title?: string;

  @IsOptional()
  @IsNotEmpty()
  genre?: string;
}
  • @IsOptional() → 해당 필드를 아예 안 보내도 에러가 나지 않음
  • 조건부 유효성 검사가 가능해짐 (값이 있으면 유효성 검사, 없으면 스킵)

 

핵심 요약

  • class-validator는 런타임 유효성 검사를 위한 핵심 도구
  • DTO에 데코레이터만 붙이면 코드 분리 + 가독성 + 재사용성 향상
  • @IsNotEmpty, @IsOptional 등으로 API의 입력 검증을 간단하고 안전하게 구현 가능
  • 실수로 잘못된 데이터를 보내더라도 백엔드에서 방어 가능

                                                                                                               

학습 후기                                                                                                                                       

NestJS에서 DTO와 class-validator를 함께 사용하는 방식은 단순히 코드 구조를 깔끔하게 만들 뿐 아니라, 실질적인 런타임 안정성까지 제공해준다는 점에서 매우 인상 깊었습니다. 이전까지는 타입스크립트의 타입만으로도 어느 정도 검증이 된다고 착각했지만, 실제로는 런타임에서는 타입이 무의미하다는 것을 직접 테스트를 통해 깨달을 수 있었습니다. 특히 필드를 비워서 요청해도 아무 문제없이 넘어가는 상황을 보며, class-validator의 필요성을 실감했습니다.

 

DTO를 통해 요청 body를 구조화해 전달받으니 컨트롤러 코드가 훨씬 간결해졌고, 인자 나열 없이도 .title, .genre처럼 접근이 가능해져 가독성이 좋아졌습니다. 또한 update 요청처럼 일부 필드만 받을 수 있는 상황에서 @IsOptional()과 @IsNotEmpty()를 조합해 조건부 검증을 구현하는 방식은 매우 직관적이면서도 유연했습니다. 이러한 구문이 단 몇 줄의 데코레이터로 구현된다는 것이 놀라웠습니다.

 

또한 class-transformer의 @Type()과 @Transform() 기능 덕분에 중첩 객체나 커스텀 값 변환도 간편하게 처리할 수 있어, 단순한 데이터 전달을 넘어서 실제로 필요한 형태로 데이터를 다듬어 전달할 수 있었습니다. validation과 transformation이 각각의 역할을 분담하며 유기적으로 동작하는 구조는 NestJS의 설계 철학이 잘 드러나는 부분이라고 생각했습니다.

결론적으로 DTO + class-validator 조합은 견고한 API를 구축하기 위한 핵심 기반이 되었으며, 앞으로의 모든 NestJS 프로젝트에서 필수적으로 사용해야 할 요소라고 느꼈습니다.

 

학습 인증샷       

수강 인증 사진

                         

학습 인증샷

                       

공부 시작 시간

                                                                       

공부 종료 시간

https://abit.ly/lisbva

 

Abit.ly 다운받기

 

abit.ly