
백엔드 개발자를 준비하면서 생긴 궁금증을 정리한 포스트입니다.
API에서 JSON 데이터로 사용자 입력을 받다 보면,
값이 비어 있는지 또는 올바른 형식의 값이 들어왔는지 확인해야 할 때가 있습니다.
이번 포스트에서는 사용자의 입력값이 유효하지 않을 때 오류 메시지를 표시할 수 있도록 도와주는
Validation에 대해 정리해보겠습니다.
Valid는 ‘유효한’이라는 뜻이고,
Validation은 어떤 값이 정해진 조건에 맞는지 검사하는 과정을 의미합니다.
Spring Boot에서는 이 Validation 기능을 활용해
클라이언트가 보낸 데이터가 올바른 형식인지,
또는 필요한 값이 빠지지 않았는지를 확인할 수 있습니다. :contentReference[oaicite:2]{index=2}
예를 들어 이메일을 입력받는다고 가정해보겠습니다.
클라이언트는 단순히 String 타입의 값을 보낼 수 있지만,
서버 입장에서는 그 문자열이 실제로 이메일 형식을 지키고 있는지도 함께 확인해야 합니다.
이처럼 단순히 타입만 맞는 것이 아니라, 요구사항에 맞는 값인지 검사하는 작업이 바로 검증입니다. :contentReference[oaicite:3]{index=3}
DTO는 보통 데이터를 담아서 전달하는 역할을 합니다.
그런데 별도의 검증이 없다면 제목이 비어 있어도 API가 성공으로 처리되고,
그 값이 그대로 데이터베이스에 저장될 수 있습니다.
하지만 실제 서비스에서는
“제목은 반드시 입력해야 한다”, “사용자 ID는 1 이상이어야 한다”, “이메일 형식이어야 한다”처럼
각 프로퍼티마다 지켜야 할 조건이 존재합니다.
따라서 DTO에 적절한 Validation을 적용하면
잘못된 데이터가 서비스 로직이나 데이터베이스까지 전달되기 전에 미리 막을 수 있습니다. :contentReference[oaicite:4]{index=4}
Spring Boot에서는 spring-boot-starter-validation 의존성을 추가하면
Bean Validation 기반의 검증 기능을 사용할 수 있습니다.
스프링 부트는 검증 구현체가 클래스패스에 있을 때 검증 기능을 연동해 사용할 수 있도록 지원합니다. :contentReference[oaicite:5]{index=5}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-validation")
}
이 라이브러리를 사용하면 DTO의 프로퍼티에 어노테이션을 붙이는 방식으로
간단하게 검증 규칙을 적용할 수 있습니다. (Home)
Validation에서는 다양한 제약 조건 어노테이션을 제공합니다.
@NotNull : 값이 null이 아닌지 검사@NotEmpty : 값이 null이 아니고 비어 있지 않은지 검사@NotBlank : 값이 null이 아니고 공백만 있는 문자열이 아닌지 검사@AssertTrue : 값이 true인지 검사@Size : 문자열, 컬렉션, 배열 등의 길이나 크기가 범위 안에 있는지 검사@Min : 지정한 최솟값 이상인지 검사@Max : 지정한 최댓값 이하인지 검사@Pattern : 지정한 정규식 패턴과 일치하는지 검사 (자카르타® EE)특히 문자열 검증에서는 다음 차이를 기억해두면 좋습니다.
@NotNull : null만 허용하지 않음@NotEmpty : null과 ""를 허용하지 않음@NotBlank : null, "", " " 같은 공백 문자열도 허용하지 않음 (자카르타® EE)@Valid 사용하기검증 어노테이션은 DTO 프로퍼티 위에 붙이고,
컨트롤러에서는 @RequestBody 앞에 @Valid를 붙여 검증을 적용할 수 있습니다.
Spring MVC에서는 @RequestBody와 @Valid를 함께 사용하면
요청 본문을 객체로 변환한 뒤 Bean Validation을 수행합니다. (Home)
// DTO
data class PostRequestDto(
var id: Long?,
@field:NotBlank(message = "제목은 반드시 입력해야 합니다!")
var title: String,
@field:NotBlank(message = "내용은 반드시 입력해야 합니다!")
var post: String,
@field:Min(value = 1, message = "유효하지 않은 사용자입니다.")
var userId: Long,
var isPublic: Boolean
)
/**
* 게시글을 생성하는 API
*/
@PostMapping
private fun postPost(
@Valid @RequestBody postRequestDto: PostRequestDto
): ResponseEntity<BaseResponse<PostResponseDto>> {
val result = postService.postPosts(postRequestDto)
return ResponseEntity.status(HttpStatus.CREATED)
.body(BaseResponse(data = result))
}
위 코드에서는 title, post, userId에 대해 검증 규칙을 지정했고,
컨트롤러에서 @Valid를 사용해 요청이 들어올 때 자동으로 검증이 수행되도록 하였습니다.
즉, 유효하지 않은 값이 들어오면 서비스 로직까지 도달하기 전에 예외가 발생하게 됩니다. (Home)
검증에 실패하면 Spring MVC에서는 MethodArgumentNotValidException이 발생할 수 있습니다.
이 예외는 @Valid가 적용된 요청 객체 검증에 실패했을 때 사용되며,
예외 객체 안에는 어떤 필드가 왜 실패했는지에 대한 정보가 들어 있습니다. (Home)
따라서 @RestControllerAdvice와 @ExceptionHandler를 활용하면
검증 실패 결과를 원하는 응답 형식으로 가공해 내려줄 수 있습니다.
@RestControllerAdvice
class CommonExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException::class)
protected fun methodArgumentNotValidExceptionHandler(
exception: MethodArgumentNotValidException
): ResponseEntity<BaseResponse<Map<String, String>>> {
val errors = mutableMapOf<String, String>()
exception.bindingResult.allErrors.forEach { error ->
val fieldName = (error as FieldError).field
val errorMsg = error.defaultMessage
errors[fieldName] = errorMsg ?: "에러 메시지가 존재하지 않습니다!"
}
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(
BaseResponse(
status = ResultStatus.ERROR.name,
data = errors,
resultMsg = ResultStatus.ERROR.msg,
)
)
}
}
이 코드는 검증에 실패한 필드명과 메시지를 모아서
BaseResponse 형식으로 응답해주는 예시입니다.
이런 방식으로 처리하면 클라이언트 입장에서도 어떤 입력이 왜 잘못되었는지 명확하게 확인할 수 있습니다. (Home)

Validation은 사용자의 입력값이 요구사항에 맞는지 확인하기 위한 기능입니다.
Spring Boot에서는 DTO에 검증 어노테이션을 붙이고,
컨트롤러에서 @Valid를 사용해 요청 시점에 자동으로 검증을 수행할 수 있습니다.
또한 검증에 실패했을 때 MethodArgumentNotValidException을 처리하면
프로젝트에 맞는 형태의 오류 응답도 직접 구성할 수 있습니다. (Home)
즉, Validation은 단순히 오류를 막는 기능이 아니라
잘못된 데이터가 시스템 안으로 들어오지 않도록 하는 첫 번째 방어선이라고 볼 수 있습니다.