Careeroza
Validation Error Response
Returning Field Errors
Clients (and your React form) need to know which field failed and why. Handle MethodArgumentNotValidException and return the field errors. (The next module covers @RestControllerAdvice in depth.)
@RestControllerAdvice
public class ValidationErrorHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ProblemDetail handle(MethodArgumentNotValidException ex) {
Map<String, String> errors = new LinkedHashMap<>();
ex.getBindingResult().getFieldErrors()
.forEach(e -> errors.putIfAbsent(e.getField(), e.getDefaultMessage()));
ProblemDetail pd = ProblemDetail.forStatusAndDetail(HttpStatus.BAD_REQUEST, "Request has invalid fields");
pd.setTitle("Validation failed");
pd.setProperty("errors", errors);
return pd;
}
}Example
curl -i -X POST localhost:8080/api/products -H "Content-Type: application/json" -d '{"name":"","price":-5,"stock":10,"category":""}'Example output
HTTP/1.1 400 Bad Request
Content-Type: application/problem+json
{"type":"about:blank","title":"Validation failed","status":400,"detail":"Request has invalid fields","instance":"/api/products","errors":{"name":"must not be blank","price":"must be greater than or equal to 0.01","category":"category is required"}}Note: The order of field errors is not guaranteed by Hibernate Validator. If the order matters to you (for tests), sort the field names.
Custom Messages
Put messages in src/main/resources/ValidationMessages.properties to keep them out of code (and translate them later):
Example
ValidationMessages.properties
product.name.required=Please enter a product name
product.price.min=Price must be at least {value}@NotBlank(message = "{product.name.required}") String name,
@DecimalMin(value = "0.01", message = "{product.price.min}") BigDecimal price