포스트

2023-10-18-TIL

Today I Learned

Custom Error Message with @Size

@Size는 Bean Validation의 제약 애너테이션으로, 값의 크기가 min과 max 사이(양 끝 포함)인지 검사한다. Jakarta Bean Validation Javadoc에 따르면 문자열이면 길이를, 컬렉션과 맵이면 크기를, 배열이면 길이를 본다. null은 유효한 값으로 취급한다. 그래서 필수 값이면서 길이도 제한하려면 @NotNull이나 @NotBlank를 함께 붙여야 한다.

기본 메시지는 {jakarta.validation.constraints.Size.message}라는 템플릿이다. message 속성에 원하는 문구를 넣으면 바꿀 수 있고, 문구 안에서 {min}, {max}처럼 애너테이션 속성 값을 참조할 수 있다.

1
2
3
4
5
public record SignUpRequest(
    @NotBlank
    @Size(min = 2, max = 20, message = "닉네임은 {min}자 이상 {max}자 이하로 입력해 주세요.")
    String nickname
) {}

Hibernate Validator 레퍼런스는 이런 메시지 템플릿을 ValidationMessages.properties 리소스 번들에서 찾아 값을 채운다고 설명한다. 문구를 코드에 직접 쓰는 대신 message = "{nickname.size}"처럼 키만 두고 번들에 문구를 모으면 다국어 처리와 수정이 쉬워진다.

메시지를 정했으면 응답으로 내려 주는 부분도 필요하다. 컨트롤러 메서드의 @Valid @RequestBody 인자가 검증에 실패하면 Spring은 MethodArgumentNotValidException을 던진다(Spring Javadoc). 이 예외는 BindingResult를 담고 있어서 getFieldErrors()로 필드별 오류와 메시지를 꺼낼 수 있다. 링크한 글들처럼 @RestControllerAdvice에서 이 예외를 받아 필드 이름과 메시지를 응답 본문으로 바꾸는 방식이 일반적이다.

1
2
3
4
5
6
7
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, String>> handle(MethodArgumentNotValidException e) {
    Map<String, String> errors = new HashMap<>();
    e.getFieldErrors().forEach(error ->
        errors.put(error.getField(), error.getDefaultMessage()));
    return ResponseEntity.badRequest().body(errors);
}
  • https://www.baeldung.com/global-error-handler-in-a-spring-rest-api
  • https://salithachathuranga94.medium.com/validation-and-exception-handling-in-spring-boot-51597b580ffd
이 글은 저작권자의 CC BY 4.0 라이선스를 따릅니다.

댓글

아직 댓글이 없습니다