NestJS 쿼리 파라미터에 DTO를 사용해 유효성 검사 수행하기

제이슨·2024년 6월 27일
1
post-thumbnail

배경

페이지네이션 적용 코드를 작성하던 중 '값 유효성 검사'의 필요성을 느꼈다.

그 이유는

  1. 문자 값이 인자 값(page, size)으로 들어가면 안된다
  2. 음수 값이 페이지네이션 값(page와 size)에 들어가면 안된다.
  3. 데이터베이스 부하 관리를 위해서 과도한 크기의 페이지 요청을 제한해야 한다.

이렇게 두 가지였다.

문제 해결 방법

1. ParseIntPipe 사용하기

첫번째 방법은 parseIntPipe 만을 이용하여 숫자 유효성 검사만 수행한 뒤, 나머지 유효성 검사를 서비스 단에서 하는 것이다.

이 방법을 사용하면

  • "데이터베이스를 통해 확인할 필요가 없는(유저 id가 작성자 id랑 같은지를 검사한다든가 하는..) 유효성 검사 로직을 Service 단에서 해주는 게 맞는 걸까?"라는 의문이 든다.
  • 아래와 같이 커스텀 에러 메시지를 넣어주다 보면 컨트롤러 코드가 꽤나 복잡해진다
    @Query('page', new ParseIntPipe({ 
        errorHttpStatusCode: HttpStatus.BAD_REQUEST,
        exceptionFactory: (error) => new BadRequestException('페이지 번호는 숫자여야 합니다.')
      })) page: number,
  • 범위를 검사해주는 유효성 검사 로직을 서비스에 매번 넣어줘야 해서 휴먼 에러 가능성이 커진다.

2. ValidationPipe 사용하기

두번째 방법은 class-validator와 class-transformer를 사용하는 방법이다.

초기 세팅 방법은 Nest 공식문서를 참고하자.

초기 셋팅이 끝났다는 가정 하에, 적용 과정은 아래와 같다.

2-1 페이지네이션 DTO 만들기

DTO를 사용했기 때문에, 더 많은 유효성 검사를 ValidationPipe를 통해 수행할 수 있다.

  1. 문자 값이 인자 값(page, size)으로 들어가면 안된다
    -> @IsInt를 사용해 정수만을 입력받게 만듦
  2. 음수 값이 페이지네이션 값(page와 size)에 들어가면 안된다.
    -> @Min, @Max 데코레이터를 사용한 범위 제한
  3. 데이터베이스 부하 관리를 위해서 과도한 크기의 페이지 요청을 제한해야 한다.
    -> @Min, @Max 데코레이터를 사용한 범위 제한

@Type(() => Number)를 사용한 이유는 쿼리 파라미터는 문자열로 들어오게 되는데, 해당 필드 값을 숫자형으로 변환하기 위해서다.

추가적으로,

  • 디폴트 쿼리 값을 선택적 매개변수기본값 할당 을 통해 지정
  • 예외 메시지를 dto 파일 내부에서 관리할 수 있게 되어 컨트롤러 코드와 메시지 분리

와 같은 이점을 얻게 되었다.

2-2 컨트롤러에 DTO 쿼리로 받기

선택

첫번째 방법인 ParseIntPipe만을 사용하는 방법은 간단한 것처럼 보이지만,

  • 컨트롤러 단에서 할 수 있는 유효성 검사 로직이 제한적이고
  • 이에 따라 복잡한 유효성 검사 로직을 DB 값과 비교를 통한 검증이 필요하지 않은 상황에도 불구하고 서비스 레이어에 추가해야 하는 단점이 있다.

반면, ValidationPipe와 DTO를 조합하여 사용하는 방법은 초기 설정이 필요하지만,

  • 더 다양한 유효성 검사를 파이프를 통해 가능하게 만들고
  • 서비스 레이어에 매번 유효성 검사 로직을 추가해야 하는 번거로움도 줄여준다

따라서, 나는 2번 방법을 선택했다.

profile
계속 읽고 싶은 글을 쓰고 싶어요 ☺

0개의 댓글