6

When using validation for parameters of a Spring MVC @RequestMapping method, Spring responds with with different status codes depending on the type of the parameter:

  • For invalid @RequestBody parameters, Spring responds with 400
  • For invalid @RequestHeader, @PathVariable, and @RequestParam parameters, Spring responds with 500.

Can this be changed so that Spring responds with the same 400 response in all cases?


This is my code:

@Controller
@Validated
public class WebController {

    @RequestMapping(method = RequestMethod.POST, path = "/action")
    public ResponseEntity<String> doAction(
            @RequestHeader("Header-Name") @Valid LatinString headerValue,
            @RequestBody @Valid Struct body) {
        return new ResponseEntity<>(HttpStatus.OK);
    }
}
public class LatinString {

    @Pattern(regexp = "[A-Za-z]*")
    private String value;

    public LatinString(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }
}
public class Struct {

    @Pattern(regexp = "[A-Za-z0-9.-]{1,255}")
    private String domain;

    public String getDomain() {
        return domain;
    }
}
oberlies
  • 11,503
  • 4
  • 63
  • 110
  • Related question, but with spring-data-rest instead of plain spring-mvc: https://stackoverflow.com/questions/22029727/using-validators-in-spring-data-rest-returns-http-500-instead-of-400 I haven't checked if the solutions provided there would also work here. – oberlies Feb 27 '19 at 13:24
  • Related question, but for handling the case of a missing @RequestHeader instead of an invalid one: https://stackoverflow.com/questions/25151264/intercept-requestheader-exception-for-missing-header – oberlies Feb 27 '19 at 13:26

2 Answers2

5

I figured that one can get the right status code (400) by handling the exception type ConstraintViolationException. To do this, one needs to add the following code to the @Controller or a @ControllerAdvice:

    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseEntity<String> onValidationError(Exception ex) {
        return new ResponseEntity<String>(HttpStatus.BAD_REQUEST);
    }

Unfortunately, this doesn't include the nice error message body like for requests with invalid @RequestBody, so I wonder if there is a better solution.

oberlies
  • 11,503
  • 4
  • 63
  • 110
  • There are few constructors for `ResponseEntity` class. See my answer here: https://stackoverflow.com/questions/54328633/how-to-get-spesific-error-instead-of-internal-service-error/54328895#54328895 – Pijotrek Feb 27 '19 at 12:47
  • You could always return your own custom object as body: new ResponseEntity<>(new ApiErrors(message, errors), HttpStatus.BAD_REQUEST); – Romas Augustinavičius Feb 27 '19 at 13:05
  • 1
    I know that I can try to mimic the behaviour of the built-in handler for `@RequestBody`, but is there also a way to just reuse the code from that handler? – oberlies Feb 27 '19 at 13:13
2

The following solution worked for me. MissingRequestHeaderException.class this class defined my exception.

@ExceptionHandler({BadRequestException.class, ConstraintViolationException.class, MissingRequestHeaderException.class})
public ResponseEntity<Object> batRequestException(Exception e) {
    log.info(e.getMessage());
    return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseDTO<>(null, EResponseType.BAD_REQUEST, e.getMessage(), "400"));
}
João Dias
  • 16,277
  • 6
  • 33
  • 45