Backend

Dto에서 DB 의존성을 없애보자

mechaniccoder 2023. 6. 18. 23:55

이번 시간에는 Nest.js의 DTO(Data transfer object)로부터 MongoDB 의존성을 없앴던 방법을 공유하려 합니다.
이 포스팅을 읽고 난 후에는 다음의 내용을 얻어가실 수 있습니다.

 

  • DTO로부터 특정 DB의 의존성을 제거하기

Model

User, Report model들을 코드로 확인해보죠.

user.entity.ts

@Schema()
export class User {
  id: string;

  @Prop({
    select: false,
  })
  __v?: number;

  @ApiProperty()
  @Prop()
  email: string;

  @Prop({})
  password: string;

  @Prop({
    default: true,
  })
  isAdmin: boolean;
}

report.entity.ts

@Schema()
export class Report {
  id: string;

  @Prop({ select: false })
  __v?: number;

  @Prop()
  price: number;

  @Prop()
  make: string;

  @Prop()
  model: string;

  @Prop()
  year: number;

  @Prop()
  lng: number;

  @Prop()
  lat: number;

  @Prop()
  mileage: number;

  @Prop({
    ref: User.name,
    type: mongoose.Schema.Types.ObjectId,
  })
  userId: mongoose.Types.ObjectId | string;

  @Prop({
    default: false,
  })
  approved: boolean;
}

UserReport는 one-to-Many의 관계를 가지고 있죠. Report.userId 필드를 확인해보면 Report가 Userid를 reference로 가지고 있는 것을 확인할 수 있습니다.

Create Report

report를 생성하는 API가 있다면 생성된 Report를 클라이언트에게 response body로 전달하겠죠. 이를 ReportDto라고 하겠습니다.

report.dto.ts

export class ReportDto {
  //...

  @Expose()
  userId: mongoose.Types.ObjectId;
}

mongoDB로 부터 생성된 ReportuserId 필드에 mongoose.Types.ObjectId 인스턴스를 가집니다. 바로 여기서 문제가 된다고 생각한 점이 2가지가 있습니다.

 

  • DTO가 specific한 MongoDB의 의존성을 가지고 있는 점
  • ObjectId를 string화 해야하는 점

위의 두 경우를 해결하기 위해 class-transformer 라이브러리의 Transform 데코레이터를 활용했습니다. 이 데코레이터를 사용해서 ObjectIdstring으로 바꾸는 과정을 거치게합니다.

export const TransormToString = () =>
  applyDecorators(Transform(({ obj, key }) => obj[key].toString()));

이를 적용한 후에 typing을 mongoose.Types.ObjectId가 아닌 string으로 바꿔줬습니다.

export class ReportDto {
  @Expose()
  @TransformToString()
  userId: string;
}

이렇게 MongoDB 의존성을 제거하면 미래에 다른 DB로 바꾸는 시점에 코드가 깨지는 일을 최소화시킬 수 있습니다. 물론 너무 먼 얘기일 수도 있지만 그렇지 않을 수도 있죠.


마치며

최근 Nest.js를 학습하며 회사에서 프런트엔드 뿐만이 아닌 서버 코드에서 개선할 점이 있는지 고민하고 있습니다. 그 과정에서 Dto의 사용범위를 어디까지 가져야할 것인지 즉, controller와 service 레이어 중 어디까지로 제한할지 고민을 했습니다. 다음 포스팅에서는 해당 내용에 대해 얘기해보도록 하겠습니다.