@Validation 에러메세지를 깔끔한 형식으로 응답하기

박예선·2023년 9월 12일
0

SpringBoot

목록 보기
1/1
post-thumbnail

문제 상황

비즈니스 로직에서 발생할 수 있는 예외 상황들은 CustomException으로 발생키기고, 에러코드는 ErrorCode.java enum 파일에서 관리하고 있어서 client에게 깔끔하게 예외 형식을 보내주고 있었다.

그러나 client가 api 요청을 했을 때 Form class에서 validation을 통과하지 못했을 때는 에러가 깔끔하지 못하게 발생했다.

예시

// ex) LoginForm.java
public class LoginForm {

    @Schema(description = "이메일", example = "admin@cafe.com")
    @Email(message = "이메일 형식을 확인해주세요.")
    @NotBlank(message = "이메일은 필수로 입력해야 합니다.")
    private String email;

    @Schema(description = "비밀번호", example = "admin123!")
    @Pattern(regexp = "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[~!@#$])[A-Za-z\\d~!@#$]{8,11}$"
        , message = "비밀번호는 영어 대소문자, 숫자, 특수문자(~!@#$)를 포함한 8~11 자리로 입력해야 합니다.")
    @NotBlank(message = "비밀번호는 필수로 입력해야 합니다.")
    private String password;
}

위 코드에서
@Email(message = "이메일 형식을 확인해주세요.")
@NotBlank(message = "이메일은 필수로 입력해야 합니다.")
등의 validation 어노테이션들로 인해 에러가 발생할 때,

이런 식으로...

그래서 테스트할 때도 불편하고(에러가 나면 StackTrace를 확인해야 함), 클라이언트에게도 명확한 에러메세지를 전달해줄 수 없다는 단점이 있었다.
난 client에게 message로 설정한 내용을 보내주고 싶었다.

시도 1 - 실패

CustomException에서 사용하는 ErrorCode처럼 Enum으로 관리하려니 타입에러가 났다.
개인적으로 Enum으로 관리하면 유지보수에도 좋을 것 같았는데 아쉽다.
(혹시나 방법을 아신다면 댓글 부탁드려요 🍀)

시도 2 - 성공! [ExceptionHandler]

CustomException의 에러 응답 핸들링을 위해 만들었던 ExceptionHandler에 validation 핸들러를 추가해준다.

validation을 실패하면 MethodArgumentNotValidException이 발생하기 때문에, 그 Exception을 기준으로 해서 ExceptionHandler를 추가해준 것이다!

errorCode와 errorMessage를 필드로 가진 MethodInvalidResponse 클래스를 생성 후(클래스 명과 필드명은 마음대로!) errorCode에는 form의 어떤 validation에서 에러가 났는지 담아서 보내주고, errorMessage에는 개발자가 message 속성으로 지정한 String을 담아서 보내준다.

// ExceptionHandler.java
@RestControllerAdvice
@Slf4j
public class ExceptionHandler {

    // 컨트롤러 form validation 핸들러
    @org.springframework.web.bind.annotation.ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<MethodInvalidResponse> methodInvalidException(
        final MethodArgumentNotValidException e
    ) {
        BindingResult bindingResult = e.getBindingResult();
        return ResponseEntity
            .status(HttpStatus.BAD_REQUEST)
            .body(MethodInvalidResponse.builder()
                .errorCode(bindingResult.getFieldErrors().get(0).getCode())
                .errorMessage(bindingResult.getFieldErrors().get(0).getDefaultMessage())
                .build());
    }
    
    //...기존 코드들

    @Getter
    @Builder
    public static class MethodInvalidResponse {

        private String errorCode;
        private String errorMessage;
    }
}

결과적으로 원하던 형식의 에러 뱉기 성공!!!

profile
개발 좋아 lynn08082@gmail.com

1개의 댓글

comment-user-thumbnail
2024년 1월 1일

Message에 Enum을 메세지로 쓰려고 하실 때, Enum은 런타임에 생성자를 통해 바인딩 되고, 어노테이션은 컴파일 타임에 Processing 되기 때문에 사용 하실 수 없어요! 사용하고자 하신다면, ENUM 안에 static class를 만드신 뒤 그 내부에 final로 에러메세지를 상수로 추가로 두셔야 가능합니다

답글 달기