Home > OS >  How can I return validation errors in a RFC-7807 format in Spring Boot Data Rest controllers?
How can I return validation errors in a RFC-7807 format in Spring Boot Data Rest controllers?

Time:04-06

I have a Spring repository

@RepositoryRestResource
public interface MongoIntegrationTokenRepository extends MongoRepository<IntegrationToken, String>, CrudRepository<IntegrationToken, String> {}

I've added the validation configuration to add validation support and my entity has the validation annotations:

@Configuration
class MyRestMvcConfiguration implements RepositoryRestConfigurer {

    private final LocalValidatorFactoryBean localValidatorFactoryBean;

    @Autowired
    public MyRestMvcConfiguration(LocalValidatorFactoryBean localValidatorFactoryBean) {
        this.localValidatorFactoryBean = localValidatorFactoryBean;
    }

    @Override
    public void configureValidatingRepositoryEventListener(
            ValidatingRepositoryEventListener validatingRepositoryEventListener) {
        validatingRepositoryEventListener.addValidator("beforeCreate", localValidatorFactoryBean);
        validatingRepositoryEventListener.addValidator("beforeSave", localValidatorFactoryBean);
        validatingRepositoryEventListener.addValidator("beforeSave", localValidatorFactoryBean);
    }
}

When running the create operation, if there are any validation errors, the entity creation fails but the JSON response doesn't contain any errors details.

A POST to my endpoint with invalid data simply returns:

{
  "message": "Server Error",
  "details": [
    "Validation failed"
  ]
}

I'd like to return the validation errors in the RFC7807 format. This should be possible via Spring HATEOAS or by this popular library by Zalando https://github.com/zalando/problem-spring-web but I'm unsure how they need to be wired in or which approach should be used.

CodePudding user response:

I found this lone example on Github. https://github.com/marciovmartins/problem-spring-web-starter-expanded/blob/aed5825c958fad93f4aaad022689958926cf3b4a/src/main/kotlin/com/github/marciovmartins/problem/spring/web/expanded/ProblemExceptionHandler.kt and rewrote it in Java. This seems to do it.

import java.util.List;
import java.util.stream.Collectors;

import org.springframework.data.rest.core.RepositoryConstraintViolationException;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.NativeWebRequest;
import org.zalando.problem.Problem;
import org.zalando.problem.ThrowableProblem;
import org.zalando.problem.spring.web.advice.ProblemHandling;
import org.zalando.problem.violations.Violation;

@ControllerAdvice
public class ProblemControllerAdvice implements ProblemHandling {

    @ExceptionHandler
    public ResponseEntity<Problem> handleRepositoryConstraintViolationException(RepositoryConstraintViolationException exception, NativeWebRequest request) {
        List<Violation> violationList = exception.getErrors().getAllErrors()
                .stream()
                .map(objectError -> {
                    if (objectError instanceof FieldError) {
                        return new Violation(((FieldError) objectError).getField(), objectError.getDefaultMessage());
                    }
                    return new Violation(null, objectError.getDefaultMessage());
                })
                .collect(Collectors.toList());

        ThrowableProblem problem = Problem.builder()
                .withTitle("Constraint Violation")
                .withStatus(defaultConstraintViolationStatus())
                .with("violations", violationList)
                .build();
        return create(problem, request);
    }

}
  • Related