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);
}
}