163

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?

7 Answers 7

176

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.

Sign up to request clarification or add additional context in comments.

4 Comments

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 There's a typo in the answer -- we actually need '@RestControllerAdvice', not '@RestController'.
It's not a typo. This part is related to the question and annotations on a controller
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.
98

One of the ways to do this is to 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);
    }
}

1 Comment

No need to use the null in later versions of Spring: new ResponseEntity<>(HttpStatus.NOT_FOUND)
61

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.

6 Comments

Simple, clean and consumable by a REST client.
This is not useful when you don't have a genuine exception: for example when you want to do a redirection
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: stackoverflow.com/a/62860392/7066647
This is only simple and clean if you don't really care what the response body will be.
I'm inclined to disagree with this being nice. This will IMO only be nice if the error isn't a domain error. Domain errors should not be exceptions (exceptions are application errors, exceptional cases, domain rules are not exceptions - they are rules!). The response entity is much cleaner especially in conjunction with an Either monad, where one can actually treat domain errors as an integral part of ones application (as they should be)
|
20

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.

2 Comments

I like this fluent API approach.
I like this approach, but how can you set custom message of the code? like for example code 999 "my custom message", like when you get code 500 "internal server error"
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 Comments

As this is a rather old question so you should add package and version info to which you refer.
Can you include an example implementation of ErrorBean?
3

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

}

Comments

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.