인프런 커뮤니티 질문&답변

qwe980121님의 프로필 이미지
qwe980121

작성한 질문수

탄탄한 백엔드 NestJS, 기초부터 심화까지

dto 와 entity의 유지보수

작성

·

695

1

안녕하세요. 상석님!

상석님의 강의를 듣고 공식문서와 typeorm, mongoose등의 공식문서를 함께 이용하여 nest 프로젝트를 제작중인 1년차 node js 개발자입니다.

강의 너무 잘 들었습니다.
개인적으로 프로젝트를 진행하는 중 dto파일과 entity를 어떻게 관리하면 수월할까 라는 고민을 깊게 하게 되었습니다. chat gpt나 스택오버 플로우, 구글 등 많은 검색을 해봤지만 제 실력이 부족한지 정보를 찾기가 힘들어 여쭤보게 되었습니다.


export class CreateRequestPostDto {
  @ApiProperty({ example: 'youtube uri', name: 'youtubeUri' })
  @IsUrl()
  uri: string;

  @ApiProperty({ example: 'postTitle writed for user' })
  @IsString()
  postTitle: string;

  @ApiProperty({ example: 'postDescription writed for user' })
  @IsString()
  postDescription: string;
}

export class UpdatePostDto {
  @ApiProperty({ example: 'postTitle writed for user' })
  @IsString()
  postTitle: string;

  @ApiProperty({ example: 'postDescription writed for user' })
  @IsString()
  postDescription: string;
}

위는 제가 만들고 있는 프로젝트의 일부입니다.

postTitle과 postDescription이 두 클래스에서 중복이 되는 케이스인데 상속을 이용해서
postTitle과 postDescription을 따로 빼는 방법은 제가 원하는 방향이 아닙니다.

저는 기본적인 base dto클래스를 하나 만들어 놓고 이를 재활용하는 방법을 사용하고 싶습니다.

export class BasePostClass {
  @ApiProperty({ example: 'youtube uri', name: 'youtubeUri' })
  @IsUrl()
  uri: string;

  @ApiProperty({ example: 'postTitle writed for user' })
  @IsString()
  postTitle: string;

  @ApiProperty({ example: 'postDescription writed for user' })
  @IsString()
  postDescription: string;
}

만약 위와 같은 클래스가 있다면 이를 이용해서

export class uriPostClass {
  
  uri: 위의 BasePostClass에 있는 uri 프로퍼티만을 가져와서 이 곳에서 사용하고 싶습니다.
}

이와 같이 @ApiProperty 데코레이터를 다시 적어주지 않아도 되고 BasePostClass의 프로퍼티 하나를 바꾸면 이 클래스를 이용해 다른 클래스들에 영향을 주고싶은겁니다.

uri라는 이름을 URI로 변경하면 이 다른 클래스에서도 영향을 받아 URI로 변한다거나 하다못해 서버 실행 과정에서 에러라도 발생시킬 수 있도록 하고싶습니다.

프로젝트가 커지다보니 DTO파일을 관리하기도 쉽지 않았어요. db의 컬럼 이름을 하나 바꿔주면 여기저기 dto파일을 찾아다니며 같이 바꿔줘야 했습니다. 좋은 방법이 있다면 알려주실 수 있을까요?

답변 1

1

qwe980121님의 프로필 이미지
qwe980121
질문자

import { ParseIntPipe } from '@nestjs/common';
import { ApiProperty, PickType } from '@nestjs/swagger';
import { MBTI } from '@root/database/entites/enum/user.enum';
import {
  IsAlpha,
  IsAlphanumeric,
  IsArray,
  IsDate,
  IsEmail,
  IsEnum,
  IsNotEmpty,
  IsNumber,
  IsString,
  IsUrl,
  Max,
  MaxLength,
  Min,
  MinLength,
} from 'class-validator';

class RequestPostDto {
  @ApiProperty({ example: 'only youtube URI' })
  @IsString()
  uri: string;

  @ApiProperty({ example: 'postTitle writed for user' })
  @IsString()
  postTitle: string;

  @ApiProperty({ example: 'postDescription writed for user' })
  @IsString()
  postDescription?: string;

  @ApiProperty({
    example: 'recent',
    description: 'recent : 최신순, view : 조회순',
    required: false,
  })
  order?: string;

  @ApiProperty({
    example: 'DESC',
    description: 'DESC : 내림차순 ASC : 오름차순',
    required: false,
  })
  sort?: 'DESC' | 'ASC';

  @ApiProperty({
    example: 'ENFJ',
    description:
      '해당하는 MBTI의 작성자가 작성한 게시물 필터링(아직은 하나만 가능)',
    required: false,
  })
  MBTI?: string = '';

  @ApiProperty({ example: '1', description: 'default: 1', required: false })
  page?: number = 1;

  @ApiProperty({ example: '10', description: 'default: 10', required: false })
  limit?: number = 10;

  @ApiProperty({ example: '', description: '검색 키워드', required: false })
  keyword?: string;

  postIds?: number[];
}

export class CreateRequestPostDto extends PickType(RequestPostDto, [
  'postTitle',
  `uri`,
  `postDescription`,
] as const) {}

export class UpdateRequestPostDto extends PickType(RequestPostDto, [
  'postTitle',
  `postDescription`,
] as const) {}

export class FindPostFilterDto extends PickType(RequestPostDto, [
  'order',
  `sort`,
  `MBTI`,
  `page`,
  `limit`,
  `keyword`,
  `postIds`,
] as const) {}

자문 자답입니다만 혹시 도움이 되시는 분이 있을까 답 남겨봅니다.

chat gpt와 여러 블로그를 찾아본 결과 Mapped type을 알게 되었습니다.

https://docs.nestjs.com/openapi/mapped-types#pick

공식문서에도 나와있는 내용이고 활용하여 원하는 대로 클래스를 작성하게 되었습니다.
(혹시나 더 좋은 방법이 있을 수도 있는거지만요)

위와같이 Mapped type중 PickType을 이용하면 상속을 받으면서 원하는 프로퍼티만 상속을 받을 수 있습니다. 두번 째 인자로 입력하는 배열에는 프로퍼티의 이름을 입력하게 되는데 부모 클래스에 같은 이름의 프로퍼티가 없으면 런타임시 에러가 발생하게 됩니다.

부모 클래스 하나를 바꿔서 다른 자식클래스들에 영향을 주는 것은 실패했지만 에러가 발생하게 되어 쉽게 인지할 수 있게됩니다. Mapped Type을 이용해서 DTO를 관리하는 방식은 확실하지 않지만 일반적인 방법으로 보입니다. (구글에 검색하면 관련 자료가 나오더라구요.)

더 좋은 방법을 계속 찾아보겠지만 일단은 지금의 방식을 만족하며 사용하게 될 것 같습니다. 다른 분들께 도움이 되었으면 좋겠네요!

 

팁 감사합니다 (_ _)

아직 백엔드 실무를 해보지 않아서 고민하지 않았지만, 나중에 큰 도움이 될 것 같네요 ㅎ

그런데, 픽타입으로 바꿔도 결국 이름이 바뀌면 다 찾아가면서 바꿔야 하나 보네요..?

 

JS도 강의 들으면서 익히는 중이라 잘 몰라서 여쭤봅니다만, 만약 클래스에서 ApiProperty 가 상속된다면 클래스로 하는게 편하지 않을까요?

 

qwe980121님의 프로필 이미지
qwe980121

작성한 질문수

질문하기