Validation

Validation

μœ νš¨μ„± κ²€μ‚¬λŠ” λͺ¨λ“  μ›Ή μ‘μš© ν”„λ‘œκ·Έλž¨μ— ν•„μˆ˜μ μΈ κΈ°λŠ₯μž…λ‹ˆλ‹€. λ“€μ–΄μ˜€λŠ” μš”μ²­μ„ μžλ™μœΌλ‘œ ν™•μΈν•˜κΈ° μœ„ν•΄ λ‚΄μž₯된 ValidationPipeκ°€ μ‚¬μš©ν•˜λŠ” class-validator νŒ¨ν‚€μ§€λ₯Ό ν™œμš©ν•©λ‹ˆλ‹€. ValidationPipeλŠ” λ‹€μ–‘ν•œ κ°•λ ₯ν•œ μœ νš¨μ„± 검사 κ·œμΉ™μ„ μ‚¬μš©ν•˜μ—¬ λ“€μ–΄μ˜€λŠ” ν΄λΌμ΄μ–ΈνŠΈ νŽ˜μ΄λ‘œλ“œλ₯Ό ν™•μΈν•˜λŠ” νŽΈλ¦¬ν•œ 방법을 μ œκ³΅ν•©λ‹ˆλ‹€.

Overview

νŒŒμ΄ν”„ μž₯μ—μ„œ μš°λ¦¬λŠ” λ‹¨μˆœν™”λœ 검증 νŒŒμ΄ν”„λ₯Ό λ§Œλ“œλŠ” 과정을 κ±°μ³€μŠ΅λ‹ˆλ‹€. μš°λ¦¬κ°€ μˆ˜ν–‰ν•˜λŠ” μž‘μ—…μ„ 더 잘 μ΄ν•΄ν•˜λ €λ©΄ 이 기사λ₯Ό μ½λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€. μ—¬κΈ°μ„œλŠ” 주둜 μ‹€μ œ μ‚¬μš© 사둀에 쀑점을 λ‘˜ κ²ƒμž…λ‹ˆλ‹€.

Auto-validation

이 μžμŠ΅μ„œλ₯Ό μœ„ν•΄ ValidationPipeλ₯Ό 전체 μ‘μš© ν”„λ‘œκ·Έλž¨μ— λ°”μΈλ”©ν•˜λ―€λ‘œ λͺ¨λ“  μ—”λ“œν¬μΈνŠΈκ°€ 잘λͺ»λœ λ°μ΄ν„°λ‘œλΆ€ν„° μžλ™μœΌλ‘œ λ³΄ν˜Έλ©λ‹ˆλ‹€.

async function bootstrap() {
  const app = await NestFactory.create(ApplicationModule);
  app.useGlobalPipes(new ValidationPipe());
  await app.listen(3000);
}
bootstrap();

νŒŒμ΄ν”„λ₯Ό ν…ŒμŠ€νŠΈν•˜κΈ° μœ„ν•΄ κΈ°λ³Έ μ—”λ“œν¬μΈνŠΈλ₯Ό λ§Œλ“€μ–΄ λ΄…μ‹œλ‹€.

@Post()
create(@Body() createUserDto: CreateUserDto) {
  return 'This action adds a new user';
}

그런 λ‹€μŒ CreateUserDto에 λͺ‡ 가지 μœ νš¨μ„± 검사 κ·œμΉ™μ„ μΆ”κ°€ν•˜μ‹­μ‹œμ˜€.

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

export class CreateUserDto {
  @IsEmail()
  email: string;

  @IsNotEmpty()
  password: string;
}

이제 λˆ„κ΅°κ°€κ°€ μœ νš¨ν•˜μ§€ μ•Šμ€ email둜 μ—”λ“œ 포인트λ₯Ό μš”μ²­ν•˜λ©΄ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ€ 400 Bad Requestμ½”λ“œμ™€ λ‹€μŒ 응닡 본문으둜 μ‘λ‹΅ν•©λ‹ˆλ‹€.

{
  "statusCode": 400,
  "error": "Bad Request",
  "message": [
    {
      "target": {},
      "property": "email",
      "children": [],
      "constraints": {
        "isEmail": "email must be an email"
      }
    }
  ]
}

λΆ„λͺ…νžˆ 응닡 본문은 ValidationPipe의 μœ μΌν•œ μ‚¬μš© 사둀가 μ•„λ‹™λ‹ˆλ‹€. μ—”λ“œ 포인트 κ²½λ‘œμ—μ„œ :idλ₯Ό λ°›κ³  μ‹Άλ‹€κ³  상상해 λ³΄μ‹­μ‹œμ˜€. κ·Έλž˜λ„ 숫자만 μœ νš¨ν•©λ‹ˆλ‹€. 이것은 맀우 κ°„λ‹¨ν•©λ‹ˆλ‹€.

@Get(':id')
findOne(@Param() params: FindOneParams) {
  return 'This action returns a user';
}

그리고 FindOneParamsλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

import { IsNumberString } from 'class-validator';

export class FindOneParams {
  @IsNumberString()
  id: number;
}

Disable detailed errors

였λ₯˜ λ©”μ‹œμ§€λŠ” λ„€νŠΈμ›Œν¬λ₯Ό 톡해 μ „μ†‘λœ λ°μ΄ν„°μ˜ λ¬Έμ œμ μ„ μ΄ν•΄ν•˜λŠ” 데 λ§Žμ€ 도움이 λ©λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ 일뢀 ν”„λ‘œλ•μ…˜ ν™˜κ²½μ—μ„œλŠ” μžμ„Έν•œ 였λ₯˜λ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šμ„ 수 μžˆμŠ΅λ‹ˆλ‹€.

app.useGlobalPipes(
  new ValidationPipe({
    disableErrorMessages: true,
  }),
);

이제 μ΅œμ’… μ‚¬μš©μžμ—κ²Œ 였λ₯˜ λ©”μ‹œμ§€κ°€ μ±„μ›Œμ§€μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

Stripping properties

μ’…μ’… 미리 μ •μ˜ 된 (ν—ˆμš© 된) μ†μ„±λ§Œ μ „λ‹¬ν•˜κ³  μ‹ΆμŠ΅λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, μš°λ¦¬κ°€ emailκ³Ό password 속성을 κΈ°λŒ€ν•œλ‹€λ©΄ λˆ„κ΅°κ°€κ°€ ageλ₯Ό 보낼 λ•Œ 이 속성은 μ œκ±°λ˜μ–΄ DTOμ—μ„œ μ‚¬μš©ν•  수 μ—†κ²Œ λ©λ‹ˆλ‹€. μ΄λŸ¬ν•œ λ™μž‘μ„ κ°€λŠ₯ν•˜κ²Œν•˜λ €λ©΄whitelistλ₯Ό true둜 μ„€μ •ν•˜μ‹­μ‹œμ˜€.

app.useGlobalPipes(
  new ValidationPipe({
    whitelist: true,
  }),
);

이 섀정은 ν™”μ΄νŠΈλ¦¬μŠ€νŠΈμ— ν¬ν•¨λ˜μ§€ μ•Šμ€ (λ°μ½”λ ˆμ΄ν„°μ—†μ΄) μ†μ„±μ˜ μžλ™ 제거λ₯Ό ν™œμ„±ν™”ν•©λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ μš”μ²­ 처리λ₯Ό μ™„μ „νžˆ μ€‘μ§€ν•˜κ³  μ‚¬μš©μžμ—κ²Œ 였λ₯˜ 응닡을 λ°˜ν™˜ν•˜λ €λ©΄ whitelist와 ν•¨κ»˜ forbidNonWhitelistedλ₯Ό μ‚¬μš©ν•˜μ‹­μ‹œμ˜€.

Auto payload transforming

ValidationPipeλŠ” νŽ˜μ΄λ‘œλ“œλ₯Ό ν•΄λ‹Ή DTO 클래슀둜 μžλ™ λ³€ν™˜ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 컨트둀러 λ©”μ†Œλ“œμ—μ„œ createUserDto λ˜λŠ” findOneParamsλ₯Ό μ‚΄νŽ΄λ³΄λ©΄ μ‹€μ œ ν΄λž˜μŠ€κ°€ μ•„λ‹ˆλΌλŠ” 것을 μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€. μžλ™ λ³€ν™˜μ„ ν™œμ„±ν™”ν•˜λ €λ©΄transform을true둜 μ„€μ •ν•˜μ‹­μ‹œμ˜€.

app.useGlobalPipes(
  new ValidationPipe({
    transform: true,
  }),
);

Websockets & Microservices

μ΄λŸ¬ν•œ λͺ¨λ“  지침은 μ‚¬μš©μ€‘μΈ 전솑 방법에 관계없이 WebSocketκ³Ό 마이크둜 μ„œλΉ„μŠ€λ₯Ό λͺ¨λ‘ κ³ λ €ν–ˆμŠ΅λ‹ˆλ‹€.

Learn more

μ‚¬μš©μž 지정 μœ νš¨μ„± 검사기, 였λ₯˜ λ©”μ‹œμ§€ 및 μ‚¬μš© κ°€λŠ₯ν•œ λ°μ½”λ ˆμ΄ν„°μ— λŒ€ν•œ μžμ„Έν•œ λ‚΄μš©μ„ 보렀면 이 νŽ˜μ΄μ§€λ₯Ό λ°©λ¬Έν•˜μ‹­μ‹œμ˜€.

Last updated

Was this helpful?