How to apply request body validation with error details?

Hello there, I want to apply request body validation to my Spring project
import jakarta.validation.constraints.*;

data class RequestBodyDTO(
@NotBlank(message = "ID is required.")
val iD: String
)
import jakarta.validation.constraints.*;

data class RequestBodyDTO(
@NotBlank(message = "ID is required.")
val iD: String
)
and this endpoint
import jakarta.validation.Valid
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*

@RestController()
@RequestMapping("/foo")
class Handler {
@PostMapping
fun handle(@Valid @RequestBody requestBody: RequestBodyDTO): ResponseEntity<Unit> {
return ResponseEntity.ok().build()
}
}
import jakarta.validation.Valid
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*

@RestController()
@RequestMapping("/foo")
class Handler {
@PostMapping
fun handle(@Valid @RequestBody requestBody: RequestBodyDTO): ResponseEntity<Unit> {
return ResponseEntity.ok().build()
}
}
I thought @Valid would handle it for me but actually the API consumer still gets a 400 without any error details. So the consumer doesn't know what's wrong. After googling around I think Spring doesn't do that for me out of the box. So I created an additional class
import org.springframework.http.HttpStatus
import org.springframework.validation.FieldError
import org.springframework.web.bind.MethodArgumentNotValidException
import org.springframework.web.bind.annotation.*

@ControllerAdvice
class ValidationExceptionHandler {
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException::class)
fun handleValidationException(
exception: MethodArgumentNotValidException
): Map<String, String?> {
return exception.bindingResult.allErrors.associate { error ->
val fieldName = (error as FieldError).field
val errorMessage = error.defaultMessage

fieldName to errorMessage
}
}
}
import org.springframework.http.HttpStatus
import org.springframework.validation.FieldError
import org.springframework.web.bind.MethodArgumentNotValidException
import org.springframework.web.bind.annotation.*

@ControllerAdvice
class ValidationExceptionHandler {
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException::class)
fun handleValidationException(
exception: MethodArgumentNotValidException
): Map<String, String?> {
return exception.bindingResult.allErrors.associate { error ->
val fieldName = (error as FieldError).field
val errorMessage = error.defaultMessage

fieldName to errorMessage
}
}
}
Unfortunately the result is the same, the API consumer won't get any error details. Is something missing? Do I even need the ValidationExceptionHandler ? How do I achieve this? Thanks! πŸ™‚
25 Replies
JavaBot
JavaBotβ€’4w ago
βŒ› This post has been reserved for your question.
Hey @Garzec! Please use /close or the Close Post button above when your problem is solved. Please remember to follow the help guidelines. This post will be automatically marked as dormant after 300 minutes of inactivity.
TIP: Narrow down your issue to simple and precise questions to maximize the chance that others will reply in here.
ayylmao123xdd
ayylmao123xddβ€’4w ago
you can create a class that sums up all the validation errors and return it to the consumer so you get something like "error_message": "ID is required." which is basically something that ur trying to do also try using @RestControllerAdvice
Garzec
GarzecOPβ€’4w ago
would you mind telling me how to do this? ValidationExceptionHandler is wrong?
ayylmao123xdd
ayylmao123xddβ€’4w ago
BezKoder
@RestControllerAdvice example in Spring Boot - BezKoder
In this tutorial, we’re gonna look at an Spring Boot example that uses @RestControllerAdvice for exception handling in Restful API. I also show you the comparison between @RestControllerAdvice and @ControllerAdvice along with the use of @ExceptionHandler annotation. Related Posts: – @RestController vs @Controller – Spring Boot, Spring Data JPA –...
ayylmao123xdd
ayylmao123xddβ€’4w ago
and no its not wrong
@ExceptionHandler(value = {ResourceNotFoundException.class, CertainException.class})
@ResponseStatus(value = HttpStatus.NOT_FOUND)
public ErrorMessage resourceNotFoundException(ResourceNotFoundException ex, WebRequest request) {
ErrorMessage message = new ErrorMessage(
status,
date,
ex.getMessage(),
description);

return message;
}
@ExceptionHandler(value = {ResourceNotFoundException.class, CertainException.class})
@ResponseStatus(value = HttpStatus.NOT_FOUND)
public ErrorMessage resourceNotFoundException(ResourceNotFoundException ex, WebRequest request) {
ErrorMessage message = new ErrorMessage(
status,
date,
ex.getMessage(),
description);

return message;
}
from that site and that class error message will be returned to the client but yea first swap to rest controller advice
Garzec
GarzecOPβ€’4w ago
@ayylmao123xdd thank you. I tried to follow the blog post and just changed from @ControllerAdvice to @RestControllerAdvice since ErrorMessage is just a custom type, I want to make use of problem details later on Still, doesn't work 😦
JavaBot
JavaBotβ€’4w ago
If you are finished with your post, please close it. If you are not, please ignore this message. Note that you will not be able to send further messages here after this post have been closed but you will be able to create new posts.
ayylmao123xdd
ayylmao123xddβ€’4w ago
yes you need to create a custom class and it will return that class when an error happens
Garzec
GarzecOPβ€’4w ago
you mean like so?
import org.springframework.http.HttpStatus
import org.springframework.validation.FieldError
import org.springframework.web.bind.MethodArgumentNotValidException
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.ResponseStatus
import org.springframework.web.bind.annotation.RestControllerAdvice

@RestControllerAdvice
class ValidationExceptionHandler {
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException::class)
fun handleValidationException(
exception: MethodArgumentNotValidException
): ValidationErrorResponse {
val fieldErrors = exception.bindingResult.allErrors.associate { error ->
val fieldName = (error as FieldError).field
val errorMessage = error.defaultMessage

fieldName to errorMessage
}

return ValidationErrorResponse(fieldErrors)
}
}

data class ValidationErrorResponse(val fieldErrors: Map<String, String?>)
import org.springframework.http.HttpStatus
import org.springframework.validation.FieldError
import org.springframework.web.bind.MethodArgumentNotValidException
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.ResponseStatus
import org.springframework.web.bind.annotation.RestControllerAdvice

@RestControllerAdvice
class ValidationExceptionHandler {
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException::class)
fun handleValidationException(
exception: MethodArgumentNotValidException
): ValidationErrorResponse {
val fieldErrors = exception.bindingResult.allErrors.associate { error ->
val fieldName = (error as FieldError).field
val errorMessage = error.defaultMessage

fieldName to errorMessage
}

return ValidationErrorResponse(fieldErrors)
}
}

data class ValidationErrorResponse(val fieldErrors: Map<String, String?>)
That still doesn't work 😦
ayylmao123xdd
ayylmao123xddβ€’4w ago
so what happens when the id is invalid
Garzec
GarzecOPβ€’4w ago
nothing, when I set a breakpoint, it won't run the function
ayylmao123xdd
ayylmao123xddβ€’4w ago
but what happens when the id is invalid does it return the full stacktrace
Garzec
GarzecOPβ€’4w ago
you only get a 400 with
{
"timestamp": "2025-01-12T18:11:01.102+00:00",
"path": "/foo",
"status": 400,
"error": "Bad Request",
"requestId": "2e927c69-2"
}
{
"timestamp": "2025-01-12T18:11:01.102+00:00",
"path": "/foo",
"status": 400,
"error": "Bad Request",
"requestId": "2e927c69-2"
}
ayylmao123xdd
ayylmao123xddβ€’4w ago
and you want the "ID is required" right
Garzec
GarzecOPβ€’4w ago
yes please
ayylmao123xdd
ayylmao123xddβ€’4w ago
exception.getFieldErrors().forEach(fieldError ->
validationError.addViolation(fieldError.getField(), fieldError.getDefaultMessage()));
exception.getFieldErrors().forEach(fieldError ->
validationError.addViolation(fieldError.getField(), fieldError.getDefaultMessage()));
you can do something like this basically in that method argument not valid exception you run the get field errors and just add it to a lsit
Garzec
GarzecOPβ€’4w ago
sorry, the function handleValidationException never runs if /foo is valid, it executes the rest handler, if it's invalid then Spring responds with a 400, so handleValidationException never runs
ayylmao123xdd
ayylmao123xddβ€’4w ago
but it returns this change the response status to maybe not found
Garzec
GarzecOPβ€’4w ago
yes, the default Spring behavior for invalid request bodies I guess
ayylmao123xdd
ayylmao123xddβ€’4w ago
and see if that changes anything
@ResponseStatus(HttpStatus.NOT_FOUND)
@ResponseStatus(HttpStatus.NOT_FOUND)
set to this and see if it changes the error code should be 404 instead of 400
Garzec
GarzecOPβ€’4w ago
no, same for INTERNAL_SERVER_ERROR Is there some Spring magic required? Do I have to place this exception handler file into a specific directory with a conventional name or so...
ayylmao123xdd
ayylmao123xddβ€’4w ago
hmmmmmmmm
@RestControllerAdvice
public class CustomExceptionHandler {
@ExceptionHandler({yourerrorhere.class})
@ResponseStatus(HttpStatus.NOT_FOUND)
public ErrorHandler handleNotFoundExceptions(RuntimeException exception) {
return new ErrorHandler(exception.getMessage());
}

@Getter
@RequiredArgsConstructor
public class ErrorHandler {
private final String message;
}
@RestControllerAdvice
public class CustomExceptionHandler {
@ExceptionHandler({yourerrorhere.class})
@ResponseStatus(HttpStatus.NOT_FOUND)
public ErrorHandler handleNotFoundExceptions(RuntimeException exception) {
return new ErrorHandler(exception.getMessage());
}

@Getter
@RequiredArgsConstructor
public class ErrorHandler {
private final String message;
}
can you try doing something like this errorhandler is a separate class also make sure you are using the correct notblank annotation from jakarta.validation.constraints
Garzec
GarzecOPβ€’4w ago
yes, I think I got this ( as shown in my code above )
ayylmao123xdd
ayylmao123xddβ€’4w ago
ok so try with the example i sent
JavaBot
JavaBotβ€’4w ago
πŸ’€ Post marked as dormant
This post has been inactive for over 300 minutes, thus, it has been archived. If your question was not answered yet, feel free to re-open this post or create a new one. In case your post is not getting any attention, you can try to use /help ping. Warning: abusing this will result in moderative actions taken against you.

Did you find this page helpful?