151

I am using Spring Boot for a simple REST API and would like to return a correct HTTP statuscode if something fails.

@RequestMapping(value="/rawdata/", method = RequestMethod.PUT)
@ResponseBody
@ResponseStatus( HttpStatus.OK )
public RestModel create(@RequestBody String data) {
    // code ommitted..
    // how do i return a correct status code if something fails?
}

Being new to Spring and Spring Boot, the basic question is how do i return different status codes when something is ok or fails?

Marco
  • 15,101
  • 33
  • 107
  • 174

7 Answers7

162

There are several options you can use. Quite good way is to use exceptions and class for handling called @ControllerAdvice:

@ControllerAdvice
class GlobalControllerExceptionHandler {
    @ResponseStatus(HttpStatus.CONFLICT)  // 409
    @ExceptionHandler(DataIntegrityViolationException.class)
    public void handleConflict() {
        // Nothing to do
    }
}

Also you can pass HttpServletResponse to controller method and just set response code:

public RestModel create(@RequestBody String data, HttpServletResponse response) {
    // response committed...
    response.setStatus(HttpServletResponse.SC_ACCEPTED);
}

Please refer to the this great blog post for details: Exception Handling in Spring MVC


NOTE

In Spring MVC using @ResponseBody annotation is redundant - it's already included in @RestController annotation.

informatik01
  • 16,038
  • 10
  • 74
  • 104
Jakub Kubrynski
  • 13,724
  • 6
  • 60
  • 85
  • Just as comment, i did a test 15 minutes ago, and a '@RestController' without the '@ResponseBody' annotation over his method placed the string returned not inside the body but as ForwardedURL. I'm pretty noob with spring/springboot my self so can't point out why – Anearion Sep 20 '16 at 14:41
  • @Anearion There's a typo in the answer -- we actually need '@RestControllerAdvice', not '@RestController'. – yoliho Aug 15 '17 at 00:24
  • It's not a typo. This part is related to the question and annotations on a controller – Jakub Kubrynski Aug 15 '17 at 12:52
  • 1
    Note, that `javax.servlet.http.HttpServletResponse` seems to not have all the StatusCodes that `org.springframework.http.HttpStatus` does. So you can use `HttpStatus.UNPROCESSABLE_ENTITY.value()` to pass the int-value into response.setStatus. **Also** this perfectly works for error-handling using `@ExceptionHandler`. – Igor Apr 06 '18 at 11:41
82

One of the way to do this is you can use ResponseEntity as a return object.

@RequestMapping(value="/rawdata/", method = RequestMethod.PUT)
public ResponseEntity<?> create(@RequestBody String data) {
    if(everything_fine) {
        return new ResponseEntity<>(RestModel, HttpStatus.OK);
    } else {
        return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}
Ahmed Ashour
  • 5,179
  • 10
  • 35
  • 56
Ankit Basarkar
  • 1,239
  • 3
  • 12
  • 13
  • 12
    No need to use the null in later versions of Spring: new ResponseEntity<>(HttpStatus.NOT_FOUND) – Kong Oct 03 '18 at 11:22
52

A nice way is to use Spring's ResponseStatusException

Rather than returning a ResponseEntityor similar you simply throw the ResponseStatusException from the controller with an HttpStatus and cause, for example:

throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Cause description here");

This results in a response to the client containing the HTTP status:

{
  "timestamp": "2020-07-09T04:43:04.695+0000",
  "status": 400,
  "error": "Bad Request",
  "message": "Cause description here",
  "path": "/test-api/v1/search"
}

Note: HttpStatus provides many different status codes for your convenience.

Continuity8
  • 2,403
  • 4
  • 19
  • 34
  • 2
    Simple, clean and consumable by a REST client. – Alecz Sep 03 '20 at 13:15
  • This is not useful when you don't have a genuine exception: for example when you want to do a redirection – Mahdi Feb 08 '22 at 21:36
  • 2
    I'm afraid this approach is not so clean as it might be due to the way the framework works. The message is not included in the response body by default unless you configure a property called `erver.error.include-message=always`. See this answer: https://stackoverflow.com/a/62860392/7066647 – dbaltor May 07 '22 at 14:30
  • 1
    This is only simple and clean if you don't really care what the response body will be. – Jon Jun 08 '22 at 16:02
17

In case you want to return a custom defined status code, you can use the ResponseEntity as here:

@RequestMapping(value="/rawdata/", method = RequestMethod.PUT)
public ResponseEntity<?> create(@RequestBody String data) {
    int customHttpStatusValue = 499;
    Foo foo = bar();
    return ResponseEntity.status(customHttpStatusValue).body(foo);
}

The CustomHttpStatusValue could be any integer within or outside of standard HTTP Status Codes.

Vedant Goenka
  • 411
  • 4
  • 5
6

Try this code:

@RequestMapping(value = "/validate", method = RequestMethod.GET, produces = "application/json")
public ResponseEntity<ErrorBean> validateUser(@QueryParam("jsonInput") final String jsonInput) {
    int numberHTTPDesired = 400;
    ErrorBean responseBean = new ErrorBean();
    responseBean.setError("ERROR");
    responseBean.setMensaje("Error in validation!");

    return new ResponseEntity<ErrorBean>(responseBean, HttpStatus.valueOf(numberHTTPDesired));
}
2

There are different ways to return status code, 1 : RestController class should extends BaseRest class, in BaseRest class we can handle exception and return expected error codes. for example :

@RestController
@RequestMapping
class RestController extends BaseRest{

}

@ControllerAdvice
public class BaseRest {
@ExceptionHandler({Exception.class,...})
    @ResponseStatus(value=HttpStatus.INTERNAL_SERVER_ERROR)
    public ErrorModel genericError(HttpServletRequest request, 
            HttpServletResponse response, Exception exception) {
        
        ErrorModel error = new ErrorModel();
        resource.addError("error code", exception.getLocalizedMessage());
        return error;
    }
Manju D
  • 111
  • 2
1

I think the easiest way is to make return type of your method as

ResponseEntity<WHATEVER YOU WANT TO RETURN>

and for sending any status code, just add return statement as

return ResponseEntity.status(HTTP STATUS).build();

For example, if you want to return a list of books,

public ResponseEntity<List<books>> getBooks(){

  List<books> list = this.bookService.getAllBooks();
  
  if(list.size() <= 0)
     return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
  else
     return ResponseEntity.of(Optional.of(list));

}
Anmol Jain
  • 336
  • 4
  • 12