long story short: I'm creating API that is supposed to be 100% REST. I'm trying to overwrite default response for the following case: I've got a method in my @RestController that has @RequestBody as an attribute
@RequestMapping(value = {"register"}, method = RequestMethod.POST, produces = "application/hal+json")
public Resource<User> registerClient(@RequestBody User user, HttpServletRequest request)
and the method is working just fine if I send a proper request. But there is a problem when I don't. When a request has empty body, I get a generic Tomcat error page for status 400 and I need it to send just a string or a JSON object instead.
So far I tried to add Exception Handlers in my RestControllerAdvice for all Spring exceptions from package org.springframework.web.binding, but it didn't work either.
I'm already aware that for some security-related errors one have to create handlers in configuration, but I don't know if this is the case.
Did anyone face similar issues? Is there something I'm missing?
Simply put, the @RequestBody annotation maps the HttpRequest body to a transfer or domain object, enabling automatic deserialization of the inbound HttpRequest body onto a Java object. Spring automatically deserializes the JSON into a Java type, assuming an appropriate one is specified.
Thanks. spring v5. 3.6 supports request body with GET.
requestBody consists of the content object, an optional Markdown-formatted description , and an optional required flag ( false by default). content lists the media types consumed by the operation (such as application/json ) and specifies the schema for each media type. Request bodies are optional by default.
You have to provide implementation to use your error handler, map the response to response entity and throw the exception. Create new error exception class with ResponseEntity field. Custom error handler which maps the error response back to ResponseEntity.
The solution was to simply put required = false in RequestBody annotation. After that, I could easily add some logic to throw custom exception and handle it in ControllerAdvice.
@RequestMapping(value = {"register"}, method = RequestMethod.POST, produces = "application/hal+json")
public Resource<User> registerClient(@RequestBody(required = false) User user, HttpServletRequest request){
logger.debug("addClient() requested from {}; registration of user ({})", getClientIp(request), user);
if(user == null){
throw new BadRequestException()
.setErrorCode(ErrorCode.USER_IS_NULL.toString())
.setErrorMessage("Wrong body or no body in reqest");
} (...)
Firstly I suggest you to use BindingResult
as a parameter of the POST call and check if it returns an error or not.
@RequestMapping(value = {"register"}, method = RequestMethod.POST, produces = "application/hal+json")
public ResponseEntity<?> registerClient(@RequestBody User user, HttpServletRequest request, BindingResult brs)
if (!brs.hasErrors()) {
// add the new one
return new ResponseEntity<User>(user, HttpStatus.CREATED);
}
return new ResponseEntity<String>(brs.toString(), HttpStatus.BAD_REQUEST);
}
Secondly, the call can throw some of errors, a good practice is to carch them and return them itself or transform them to your own exception object. The advantage is it secures a call of all the update/modify methods (POST, PUT, PATCH)
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public ResponseEntity<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
return new ResponseEntity<List<MethodArgumentNotValidException>>(e, HttpStatus.BAD_REQUEST);
}
@ExceptionHandler({HttpMessageNotReadableException.class})
@ResponseBody
public ResponseEntity<?> handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
return new ResponseEntity<List<HttpMessageNotReadableException>>(e, HttpStatus.BAD_REQUEST);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With