class-validator์˜ IsMongoId: MongoDB ObjectId ๊ฒ€์ฆ

class-validator์˜ IsMongoId: MongoDB ObjectId ๊ฒ€์ฆ

D
dongAuthor
7 min read

NestJS๋กœ API๋ฅผ ๊ฐœ๋ฐœํ•˜๋‹ค ๋ณด๋ฉด MongoDB ObjectId ํ˜•์‹์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๊ฒ€์ฆํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ž์ฃผ ์ƒ๊น๋‹ˆ๋‹ค. ์ž˜๋ชป๋œ ํ˜•์‹์˜ ID๊ฐ€ ๋“ค์–ด์˜ค๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ฟผ๋ฆฌ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ , ์‚ฌ์šฉ์ž์—๊ฒŒ๋Š” ๋ถˆ์นœ์ ˆํ•œ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๊ฐ€ ์ „๋‹ฌ๋˜์ฃ .

class-validator์˜ @IsMongoId() ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด ๋ฌธ์ œ๋ฅผ ๊ฐ„๋‹จํ•˜๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. DTO์— ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํ•˜๋‚˜๋งŒ ์ถ”๊ฐ€ํ•˜๋ฉด MongoDB ObjectId ๊ฒ€์ฆ์ด ์ž๋™์œผ๋กœ ์ด๋ฃจ์–ด์ง€๊ณ , ์ž˜๋ชป๋œ ์š”์ฒญ์€ ์ปจํŠธ๋กค๋Ÿฌ์— ๋„๋‹ฌํ•˜๊ธฐ ์ „์— ์ฐจ๋‹จ๋ฉ๋‹ˆ๋‹ค.

์ด ๊ธ€์—์„œ๋Š” @IsMongoId()์˜ ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•๋ถ€ํ„ฐ ๋‚ด๋ถ€ ๊ตฌํ˜„, ์‹ค์ „ ํ™œ์šฉ๋ฒ•, ๊ทธ๋ฆฌ๊ณ  ์ปค์Šคํ…€ ๊ฒ€์ฆ๊นŒ์ง€ ๋ชจ๋‘ ๋‹ค๋ค„๋ณผ๊ฒŒ์š”.

Class-Validator์™€ NestJS์˜ ๋งŒ๋‚จ

NestJS๋Š” TypeScript ๊ธฐ๋ฐ˜์˜ ๊ฐ•๋ ฅํ•œ ์„œ๋ฒ„ ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค. ๊ทธ์ค‘์—์„œ๋„ class-validator๋Š” NestJS ๊ณต์‹ ๋ฌธ์„œ์—์„œ ๊ถŒ์žฅํ•˜๋Š” ๊ฒ€์ฆ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ, ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๊ธฐ๋ฐ˜์˜ ์ง๊ด€์ ์ธ ๋ฌธ๋ฒ•์œผ๋กœ ์ž…๋ ฅ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.

class-validator๋ฅผ ๋„์ž…ํ•˜๋ฉด ์„œ๋น„์Šค ๋ ˆ์ด์–ด์—์„œ ์ผ์ผ์ด ๊ฒ€์ฆ ๋กœ์ง์„ ์ž‘์„ฑํ•  ํ•„์š”๊ฐ€ ์—†์–ด์ง‘๋‹ˆ๋‹ค. DTO์— ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ ์š”์ฒญ ๋ฐ์ดํ„ฐ์˜ ๊ตฌ์กฐ๋ฅผ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์ฃ . ์‹ค์ œ๋กœ ๋งŽ์€ ๊ฐœ๋ฐœ์ž๋“ค์ด class-validator ๋„์ž… ํ›„ ์ œํ’ˆ์˜ ์•ˆ์ •์„ฑ๊ณผ ๊ฐœ๋ฐœ ํŽธ์˜์„ฑ์ด ํฌ๊ฒŒ ํ–ฅ์ƒ๋˜์—ˆ๋‹ค๊ณ  ์ด์•ผ๊ธฐํ•ฉ๋‹ˆ๋‹ค.

@IsMongoId()๋ž€ ๋ฌด์—‡์ธ๊ฐ€?

์ •์˜์™€ ๋ชฉ์ 

@IsMongoId()๋Š” class-validator์—์„œ ์ œ๊ณตํ•˜๋Š” ๋‚ด์žฅ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋กœ, ๋ฌธ์ž์—ด์ด MongoDB ObjectId ํ˜•์‹(24์ž 16์ง„์ˆ˜)์ธ์ง€ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค.

MongoDB์—์„œ ๊ฐ ๋ฌธ์„œ๋Š” ๊ณ ์œ ํ•œ _id ํ•„๋“œ๋ฅผ ๊ฐ€์ง€๋ฉฐ, ์ด๋Š” 12๋ฐ”์ดํŠธ BSON ํƒ€์ž…์˜ ObjectId์ž…๋‹ˆ๋‹ค. ๋ฌธ์ž์—ด๋กœ ํ‘œํ˜„ํ•˜๋ฉด 24์ž๋ฆฌ 16์ง„์ˆ˜ ํ˜•ํƒœ๊ฐ€ ๋˜๋Š”๋ฐ, @IsMongoId()๋Š” ๋ฐ”๋กœ ์ด ํ˜•์‹์„ ๊ฒ€์ฆํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ์‚ฌ์šฉ ์˜ˆ์ œ

import { IsMongoId, IsNotEmpty } from 'class-validator';

export class FindUserDto {
  @IsNotEmpty()
  @IsMongoId()
  userId: string;
}

์œ„ ์˜ˆ์ œ์—์„œ userId๋Š” ๋ฐ˜๋“œ์‹œ ๋น„์–ด์žˆ์ง€ ์•Š์€ MongoDB ObjectId ํ˜•์‹์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์ž˜๋ชป๋œ ํ˜•์‹์˜ ID๊ฐ€ ์ „๋‹ฌ๋˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์—๋Ÿฌ ์‘๋‹ต์ด ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค:

{
  "statusCode": 400,
  "message": ["userId must be a mongodb id"],
  "error": "Bad Request"
}

validator.js ํ™œ์šฉ

@IsMongoId()์˜ ๋‚ด๋ถ€ ๊ตฌํ˜„์„ ์‚ดํŽด๋ณด๋ฉด ํฅ๋ฏธ๋กœ์šด ์ ์„ ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

import { ValidationOptions } from '../ValidationOptions';
import { buildMessage, ValidateBy } from '../common/ValidateBy';
import isMongoIdValidator from 'validator/lib/isMongoId';

export const IS_MONGO_ID = 'isMongoId';

export function isMongoId(value: unknown): boolean {
  return typeof value === 'string' && isMongoIdValidator(value);
}

export function IsMongoId(validationOptions?: ValidationOptions): PropertyDecorator {
  return ValidateBy(
    {
      name: IS_MONGO_ID,
      validator: {
        validate: (value): boolean => isMongoId(value),
        defaultMessage: buildMessage(
          eachPrefix => eachPrefix + '$property must be a mongodb id',
          validationOptions
        ),
      },
    },
    validationOptions
  );
}

ํ•ต์‹ฌ ํฌ์ธํŠธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  • validator.js ์˜์กด: validator/lib/isMongoId๋ฅผ ์‚ฌ์šฉํ•ด ์‹ค์ œ ๊ฒ€์ฆ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • ํƒ€์ž… ์ œํ•œ: string ํƒ€์ž…๋งŒ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • ์ •๊ทœ์‹ ๊ธฐ๋ฐ˜: 24์ž 16์ง„์ˆ˜ ํ˜•์‹์„ ์ •๊ทœ์‹์œผ๋กœ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค.
  • ์ปค์Šคํ„ฐ๋งˆ์ด์ง• ๊ฐ€๋Šฅ: validationOptions๋ฅผ ํ†ตํ•ด ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

NestJS ํ”„๋กœ์ ํŠธ์— Class-Validator ์„ค์ •ํ•˜๊ธฐ

์„ค์น˜

๋จผ์ € ํ•„์š”ํ•œ ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค:

npm i --save class-validator class-transformer

class-transformer๋Š” plain object๋ฅผ class instance๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค.

ValidationPipe ์ ์šฉ

NestJS์—์„œ class-validator์˜ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์ธ์‹ํ•˜๋ ค๋ฉด ValidationPipe๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ „์—ญ์œผ๋กœ ์ ์šฉํ•˜๊ฑฐ๋‚˜ ํŠน์ • ์ปจํŠธ๋กค๋Ÿฌ/๋ผ์šฐํŠธ์—๋งŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ „์—ญ ์ ์šฉ (main.ts):

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

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(
    new ValidationPipe({
      whitelist: true,
      forbidNonWhitelisted: true,
      transform: true,
    })
  );
  await app.listen(3000);
}
bootstrap();

์ปจํŠธ๋กค๋Ÿฌ ๋ ˆ๋ฒจ ์ ์šฉ:

import { Controller, Post, Body, UsePipes, ValidationPipe } from '@nestjs/common';

@Controller('users')
export class UserController {
  @Post('find')
  @UsePipes(new ValidationPipe({ whitelist: true, forbidNonWhitelisted: true }))
  async findUser(@Body() dto: FindUserDto) {
    return this.userService.findUserById(dto.userId);
  }
}

์ฃผ์š” ์˜ต์…˜:

  • whitelist: DTO์— ์ •์˜๋˜์ง€ ์•Š์€ ์†์„ฑ์„ ์ž๋™์œผ๋กœ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.
  • forbidNonWhitelisted: DTO์— ์—†๋Š” ์†์„ฑ์ด ํฌํ•จ๋˜๋ฉด ์š”์ฒญ์„ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค.
  • transform: plain object๋ฅผ DTO ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค๋กœ ์ž๋™ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

DTO์—์„œ @IsMongoId() ํ™œ์šฉํ•˜๊ธฐ

์‹ค์ „ ์˜ˆ์ œ: ์‚ฌ์šฉ์ž ์กฐํšŒ API

// user.dto.ts
import { IsMongoId, IsNotEmpty } from 'class-validator';

export class GetUserByIdDto {
  @IsNotEmpty({ message: 'userId๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.' })
  @IsMongoId({ message: 'userId๋Š” ์œ ํšจํ•œ MongoDB ObjectId์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.' })
  userId: string;
}
// user.controller.ts
import { Controller, Post, Body } from '@nestjs/common';

@Controller('users')
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Post('find')
  async findUser(@Body() dto: GetUserByIdDto) {
    console.log(dto.userId);
    return this.userService.findUserById(dto.userId);
  }
}

์œ ํšจํ•œ ์š”์ฒญ:

{
  "userId": "507f191e810c19729de860ea"
}

๋ฌดํšจํ•œ ์š”์ฒญ:

{
  "userId": "12345"
}

์‘๋‹ต:

{
  "statusCode": 400,
  "message": ["userId๋Š” ์œ ํšจํ•œ MongoDB ObjectId์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."],
  "error": "Bad Request"
}

์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฒ€์ฆ

์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋‚˜ URL ํŒŒ๋ผ๋ฏธํ„ฐ์—์„œ๋„ ๋™์ผํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

import { Controller, Get, Param } from '@nestjs/common';
import { IsMongoId } from 'class-validator';

export class UserIdParam {
  @IsMongoId()
  id: string;
}

@Controller('users')
export class UserController {
  @Get(':id')
  async getUser(@Param() params: UserIdParam) {
    return this.userService.findById(params.id);
  }
}

ํ”ํ•œ ๋ฌธ์ œ์™€ ํ•ด๊ฒฐ์ฑ…

๋นˆ ๋ฌธ์ž์—ด ์ฒ˜๋ฆฌ

@IsMongoId()๋Š” ๋นˆ ๋ฌธ์ž์—ด์„ ๊ฒ€์ฆํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋นˆ ๋ฌธ์ž์—ด๋„ ๊ฑฐ๋ถ€ํ•˜๋ ค๋ฉด @IsNotEmpty()๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜์„ธ์š”:

export class CreateNewsDto {
  @IsNotEmpty()
  @IsString()
  title: string;

  @IsNotEmpty()
  @IsString()
  content: string;

  @IsNotEmpty()
  @IsString()
  @IsMongoId()
  pageId: string;

  @IsOptional()
  @IsString()
  @IsMongoId()
  ownerId: string;
}

@IsOptional()์„ ์‚ฌ์šฉํ•˜๋ฉด ํ•ด๋‹น ํ•„๋“œ๊ฐ€ ์—†๊ฑฐ๋‚˜ undefined์ผ ๋•Œ๋Š” ๊ฒ€์ฆ์„ ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค.

์ปค์Šคํ…€ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€

๊ธฐ๋ณธ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๊ฐ€ ๋งˆ์Œ์— ๋“ค์ง€ ์•Š๋Š”๋‹ค๋ฉด ์ปค์Šคํ„ฐ๋งˆ์ด์ง•ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

export class FindUserDto {
  @IsMongoId({ message: '์˜ฌ๋ฐ”๋ฅธ ์‚ฌ์šฉ์ž ID ํ˜•์‹์ด ์•„๋‹™๋‹ˆ๋‹ค.' })
  userId: string;
}

๋‹ค๊ตญ์–ด ์ง€์›์ด ํ•„์š”ํ•˜๋‹ค๋ฉด i18n ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ๊ฒฐํ•ฉํ•ด ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ณ ๊ธ‰ ํ™œ์šฉ๋ฒ•๊ณผ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•

๋‹ค๋ฅธ ๊ฒ€์ฆ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์™€ ๊ฒฐํ•ฉ

์—ฌ๋Ÿฌ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์กฐํ•ฉํ•ด ๋” ์ •๊ตํ•œ ๊ฒ€์ฆ ๊ทœ์น™์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

import { IsMongoId, IsOptional, IsArray, ArrayMinSize } from 'class-validator';

export class AssignTasksDto {
  @IsArray()
  @ArrayMinSize(1)
  @IsMongoId({ each: true, message: '๊ฐ ํ•ญ๋ชฉ์€ ์œ ํšจํ•œ MongoDB ObjectId์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.' })
  userIds: string[];

  @IsMongoId()
  projectId: string;
}

{ each: true } ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐฐ์—ด์˜ ๊ฐ ์š”์†Œ๋ฅผ ๊ฐœ๋ณ„์ ์œผ๋กœ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค.

์ปค์Šคํ…€ ๊ฒ€์ฆ๊ธฐ: DB ์กด์žฌ ์—ฌ๋ถ€ ํ™•์ธ

@IsMongoId()๋Š” ํ˜•์‹๋งŒ ๊ฒ€์ฆํ•  ๋ฟ, ํ•ด๋‹น ID๊ฐ€ ์‹ค์ œ๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์กด์žฌํ•˜๋Š”์ง€๋Š” ํ™•์ธํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•œ ์ปค์Šคํ…€ ๊ฒ€์ฆ๊ธฐ๋ฅผ ๋งŒ๋“ค์–ด๋ณผ๊นŒ์š”?

import { registerDecorator, ValidationOptions, ValidationArguments, ValidatorConstraint, ValidatorConstraintInterface } from 'class-validator';
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';

@ValidatorConstraint({ name: 'IsExistingMongoId', async: true })
@Injectable()
export class IsExistingMongoIdConstraint implements ValidatorConstraintInterface {
  constructor(
    @InjectModel('User') private readonly userModel: Model<any>,
  ) {}

  async validate(value: string, args: ValidationArguments): Promise<boolean> {
    const modelName = args.constraints[0];
    
    if (modelName === 'User') {
      const user = await this.userModel.findById(value).exec();
      return !!user;
    }
    
    return false;
  }

  defaultMessage(args: ValidationArguments): string {
    return `${args.property}์— ํ•ด๋‹นํ•˜๋Š” ๋ฌธ์„œ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.`;
  }
}

export function IsExistingMongoId(
  modelName: string,
  validationOptions?: ValidationOptions,
): PropertyDecorator {
  return (object, propertyName) => {
    registerDecorator({
      name: 'IsExistingMongoId',
      target: object.constructor,
      propertyName,
      constraints: [modelName],
      options: validationOptions,
      validator: IsExistingMongoIdConstraint,
    });
  };
}

์‚ฌ์šฉ๋ฒ•:

export class UpdateUserDto {
  @IsExistingMongoId('User', { message: '์กด์žฌํ•˜์ง€ ์•Š๋Š” ์‚ฌ์šฉ์ž์ž…๋‹ˆ๋‹ค.' })
  userId: string;
}

์ปค์Šคํ…€ ๊ฒ€์ฆ๊ธฐ๋Š” ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ง€์›ํ•˜๋ฏ€๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ฟผ๋ฆฌ๋ฅผ ํ†ตํ•œ ๊ฒ€์ฆ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋งŒ ์„ฑ๋Šฅ์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์žˆ์œผ๋‹ˆ ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉํ•˜์„ธ์š”.

@IsMongoId()๋กœ ๋” ์•ˆ์ „ํ•œ API ๋งŒ๋“ค๊ธฐ

@IsMongoId()๋Š” ์ž‘์ง€๋งŒ ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ์ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํ•˜๋‚˜๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ด์ ์„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

  • ์ฝ”๋“œ ๊ฐ„์†Œํ™”: ์„œ๋น„์Šค ๋ ˆ์ด์–ด์—์„œ ๋ฐ˜๋ณต๋˜๋Š” ๊ฒ€์ฆ ๋กœ์ง์„ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ผ๊ด€์„ฑ: ๋ชจ๋“  MongoDB ObjectId ๊ฒ€์ฆ์ด ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค.
  • ์—๋Ÿฌ ํ•ธ๋“ค๋ง: ์ž˜๋ชป๋œ ์š”์ฒญ์„ ์กฐ๊ธฐ์— ์ฐจ๋‹จํ•ด ๋ถˆํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ฟผ๋ฆฌ๋ฅผ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  • ์œ ์ง€๋ณด์ˆ˜์„ฑ: DTO๋ฅผ ๋ณด๋Š” ๊ฒƒ๋งŒ์œผ๋กœ ์–ด๋–ค ๊ฒ€์ฆ์ด ์ด๋ฃจ์–ด์ง€๋Š”์ง€ ๋ช…ํ™•ํ•˜๊ฒŒ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

NestJS ํ”„๋กœ์ ํŠธ์—์„œ MongoDB๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด @IsMongoId()๋Š” ํ•„์ˆ˜ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•๋ถ€ํ„ฐ ์ปค์Šคํ…€ ๊ฒ€์ฆ๊ธฐ๊นŒ์ง€ ๋‹ค์–‘ํ•œ ํ™œ์šฉ๋ฒ•์„ ์ตํ˜€๋‘๋ฉด ๋” ๊ฒฌ๊ณ ํ•˜๊ณ  ์•ˆ์ „ํ•œ API๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์„ ๊ฑฐ์˜ˆ์š”.

์ง€๊ธˆ ๋ฐ”๋กœ ์—ฌ๋Ÿฌ๋ถ„์˜ ํ”„๋กœ์ ํŠธ์— class-validator๋ฅผ ์„ค์น˜ํ•˜๊ณ  @IsMongoId()๋ฅผ ์ ์šฉํ•ด๋ณด์„ธ์š”. ์ž‘์€ ๋ณ€ํ™”๊ฐ€ ํฐ ์ฐจ์ด๋ฅผ ๋งŒ๋“ค์–ด๋‚ผ ๊ฒ๋‹ˆ๋‹ค!

class-validator์˜ IsMongoId: MongoDB ObjectId ๊ฒ€์ฆ