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

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

NestJS

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

NangIn 2025. 4. 24. 10:36

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

 

강의 내용 정리   

 

Mapped Types 이론

 

Mapped Types란?

  • 기존 타입(Class, Interface 등)을 기반으로 부분적인 수정/조합을 자동화해주는 TypeScript의 기능
  • NestJS의 DTO 작성에서 코드 중복 제거에 매우 유용하게 사용됨

 

주요 5가지 Mapped Type 

타입명 설명
Partial<T> 모든 프로퍼티를 옵셔널로 변경
Pick<T, K> 특정 프로퍼티만 골라 사용
Omit<T, K> 특정 프로퍼티만 제외하고 사용
Intersection (A & B) 여러 타입의 모든 프로퍼티를 병합
Composition 위 모든 Mapped Type을 조합하여 사용

 

예제 중심 사용법 요약

  • Partial<T> – 가장 많이 사용하는 타입
    • 모든 속성을 옵셔널로 만들 때 사용
    • export class CreateUserDto {
        name: string;
        email: string;
        password: string;
      }
      
      export class UpdateUserDto extends PartialType(CreateUserDto) {}
      
    • 사용 맥락:
      • Create 시에는 모든 값이 필수
      • Update 시에는 일부 필드만 수정될 수 있으므로 옵셔널 처리 필요
  • Pick<T, K> – 원하는 속성만 골라 쓰기
    • export class LoginDto extends PickType(CreateUserDto, ['email', 'password']) {}
      
    • 사용 맥락:
      • 이미 정의된 DTO에서 필요한 필드만 선택해 로그인, 조회 등에 활용
  • Omit<T, K> – 특정 속성만 제외하고 쓰기
    • export class NoPasswordDto extends OmitType(CreateUserDto, ['password']) {}
      
    • 사용 맥락:
      • 응답 시 민감한 필드를 제거하거나
      • 특정 목적에 맞춰 DTO 간소화 시 유용
  • IntersectionType(A, B) – 다중 DTO 병합
    • export class FullUserDto extends IntersectionType(UserDetailDto, AddressDto) {}
      
      
    • 사용 맥락:
      • 여러 도메인 정보를 한 번에 응답할 때 유용
  • Composition – 조합 활용
    • export class UpdateCatDto extends PartialType(
        OmitType(CreateCatDto, ['name'] as const),
      ) {}
      
    • 사용 맥락:
      • 일부 필드는 제외하고, 나머지는 옵셔널 처리
      • 유연하고 재사용성 높은 DTO 구성 가능

 

Mapped Types 적용하기

 

적용 대상: DTO 클래스 간 중복 제거

  • CreateMovieDto, UpdateMovieDto를 비교해 보면,
    • 구조는 동일하고
    • Update에서는 @IsOptional()만 추가된 형태
  • 이럴 경우, PartialType으로 Create DTO를 상속받으면 됨

 

PartialType 적용 방법

// Before
export class UpdateMovieDto {
  @IsString()
  @IsOptional()
  title: string;
  ...
}

// After
export class UpdateMovieDto extends PartialType(CreateMovieDto) {}
  • @nestjs/mapped-types에서 PartialType 불러와 사용
  • CreateMovieDto의 모든 속성을 @IsOptional()로 감싸줌
  • 실제로 클래스 밸리데이터에도 영향을 미침 → PATCH 요청 시 일부 필드만 보내도 통과 가능

 

Postman 테스트 예시

  • /movies/1에 대해 title만 변경한 요청을 보냄:
  • PATCH /movies/1 { "title": "Dark Knight Rise 300" }
  • 성공적으로 요청 처리됨 → PartialType 적용으로 필수값 요구 사라짐

 

PartialType의 장점 

항목 설명
중복 제거 Create, Update DTO에서 동일한 필드 반복 정의 방지
유지보수 효율 Create DTO만 수정해도 Update에 자동 반영
밸리데이션 연동 @IsOptional() 적용 상태로 class-validator에서 정확히 처리
Nest CLI 패턴 NestJS CLI로 resource 생성 시 기본적으로 PartialType 사용 구조 제공

 

Genre/Director DTO에도 동일하게 적용

  • // UpdateGenreDto
    export class UpdateGenreDto extends PartialType(CreateGenreDto) {}
    
    // UpdateDirectorDto
    export class UpdateDirectorDto extends PartialType(CreateDirectorDto) {}
    
  • 모든 Update DTO의 중복 선언 제거
  • 확장성 향상: Create DTO만 수정하면 Update까지 반영됨
  •  

 

Serialization

 

Serialization이란?

  • 의미: 서버에서 프론트엔드로 데이터를 응답하기 전에 불필요한 필드를 제거하거나 변환하는 과정
  • 사용 목적
    • 민감하거나 내부 용도의 필드를 숨기기 위해
    • 응답 데이터를 간결하고 명확하게 만들기 위해
    • 프론트에서 불필요한 처리 비용 감소

 

현재 문제 상황

  • /movies 요청 시 다음과 같은 불필요한 필드가 노출됨:
    • __v: TypeORM 버전 필드 (내부용)
    • updatedAt: 프론트에서는 보통 필요 없음
    • createdAt: 경우에 따라 필요 없을 수 있음
    {
      "id": 1,
      "title": "Inception",
      "createdAt": "2024-01-01T00:00:00Z",
      "updatedAt": "2024-01-02T00:00:00Z",
      "version": 0
    }
    

 

해결 방법 – class-transformer 사용

  • NestJS는 class-transformer의 데코레이터를 통해 응답 데이터 필드를 조정할 수 있음
  • 불필요한 필드 숨기기
    • @Exclude() // 엔티티 상단 혹은 프로퍼티마다 사용
      updatedAt: Date;
      
      @Exclude()
      version: number;
      
    • @Exclude()는 직렬화 시 해당 필드를 제거
    • 엔티티에 직접 명시하여 모든 응답에서 일괄적으로 적용 가능
  • 필요한 필드만 노출하고 싶을 때 (선택적)
    • @Expose()
      title: string;
      
    • @Expose()만 명시한 경우, 해당 필드만 직렬화 대상으로 허용

 

적용 예시 – 무비, 장르, 다이렉터

  • @Exclude()를 아래 필드에 적용:
    • @Exclude()
      updatedAt: Date;
      
      @Exclude()
      version: number;
      
  • 각 엔티티 또는 공통 상속 클래스(예: BaseEntity)에서 처리 가능

 

결과 확인 (Postman 등)

  • 요청 결과에서 해당 필드가 더 이상 출력되지 않음
  • 응답이 훨씬 간결하고 깔끔하게 정리됨
  •  

 

학습 후기         

 

Mapped Types는 단순히 TypeScript의 문법 요소 중 하나라고 생각했지만, NestJS에서 DTO를 다룰 때 실질적으로 엄청난 효율을 가져다주는 도구임을 실감했습니다. 특히 PartialType을 사용하면 Create DTO의 구조를 그대로 유지하면서도 Update DTO에서 모든 속성을 옵셔널로 처리할 수 있어, 코드 중복을 줄이고 유지보수까지 쉬워집니다. 클래스 밸리데이터와도 연동되기 때문에, 실제 요청 데이터의 유효성 검사까지도 완벽하게 대응할 수 있었습니다.

 

PickType과 OmitType도 필요에 따라 유용하게 쓸 수 있지만, 가장 빈도가 높은 것은 확실히 PartialType이었습니다. 실무에서는 대부분의 리소스가 Create와 Update 요청을 따로 받기 때문에, 이 두 DTO 간의 관계를 PartialType 하나로 해결할 수 있는 것은 매우 실용적인 방식입니다. 또한, Create DTO에만 수정이 발생해도 Update DTO에 자동으로 반영되기 때문에, 확장성과 유지보수 측면에서도 큰 이점이 있었습니다.

 

Serialization은 단순히 보기 좋은 응답을 만드는 작업 정도로 여겼지만, 실제로는 민감 정보나 불필요한 데이터가 노출되는 것을 방지하는 보안적인 측면도 있다는 걸 알게 됐습니다. 클래스에서 @Exclude() 데코레이터 하나로 프론트엔드 응답에서 특정 필드를 제거할 수 있는 기능은 아주 직관적이고 강력했습니다. 특히 version, updatedAt처럼 프론트에서는 필요 없는 필드들이 기본적으로 포함되어 있다는 사실을 보고, 이를 자동으로 관리해주는 방식이 얼마나 중요한지 체감할 수 있었습니다.

 

결론적으로 Mapped Types와 Serialization은 NestJS의 DTO 설계를 단순히 타입 선언으로 끝내지 않고, 코드의 일관성과 응답 구조의 명확성을 함께 보장해주는 핵심 도구였습니다. 실무에서 유지보수성과 안정성을 고려할 때 반드시 습득하고 적용해야 할 기능이라고 느꼈습니다.

 

학습 인증샷       

                       

수강 인증 사진
학습 인증샷
공부 시작 시간

 

공부 종료 시간

https://abit.ly/lisbva