How to create branching results for @ResponseStatus

Viewed 139

Using @ResponseStatus allows setting the status of a Rest response in Spring. But how could this be used for different kinds of status that could come from the same request?

For example, there is a method in the controller that may return a 200 or a 404. How could I define these statuses just using @ResponseStatus in one method?

4 Answers

Typically you wouldn't do this with @ResponseStatus. Instead, you can use ResponseEntity<...> as the return type of your method. If the 'type' of returned item can change, ResponseEntity<?> or ResponseEntity<Object> works too.

For example:

@GetMapping("/{key}")
public ResponseEntity<Thing> getThing(final @PathVariable String key) {
    final Thing theThing = this.thingService.get(key);

    final ResponseEntity<?> response;
    if (theThing.someProperty()) {
         response = ResponseEntity.ok(theThing);
    } else {
         response = ResponseEntity.status(HttpStatus.NOT_MODIFIED).body(null);
    }

    return response;
}

To answer your question directly, @ResponseStatus cannot be used to send different statuses by a single method.

If you want to use @ResponseStatus, how you can handle multiple statuses is:

  • Have the controller method annotated with @ResponseStatus with the required 2xx HttpStatus. This status would be sent by the controller method in the success scenario. Usually it is used to set HttpStatus other than 200 (like 201), as 200 is the default status sent even without using @ResponseStatus.
  • Have exception handler methods annotated with @ExceptionHandler, to handle different exception scenarios, also annotated with @ResponseStatus with the corresponding HttpStatus. For eg if you want to handle a Resource not found scenario, the exception handler method can be annotated with @ResponseStatus(HttpStatus.NOT_FOUND) to send back a 404.
  • In case you don't need to send a dynamic error response, you can even mark the custom exception class with @ResponseStatus along with the required HttpStatus, and when the exception is thrown (and not caught and swallowed explicitly), the corresponding HttpStatus would be returned.

You can even leverage ResponseEntity which has a status method where you can pass the required HttpStatus and return, either in the controller method or in the exception handler method as below:

Controller method:

@GetMapping("/resource")
    public ResponseEntity<Object> getResource(){
        if(resourcePresent){
            return new ResponseEntity(resource, HttpStatus.OK);
        } else {
            return new ResponseEntity(HttpStatus.NOT_FOUND);
        }
    }
}

Exception handler method:

    @ExceptionHandler(BadRequestException.class)
    public ResponseEntity<Object> handleBadRequestException(BadRequestException exception){
        return new ResponseEntity<>(customResponse, HttpStatus.BAD_REQUEST);
    }

You cannot use @ResponseStatus to set a different status code from one method depending on branching results.

You will have to return a ResponseEntity or manipulate the HttpServletResponse directly in your method (or eventually throw exceptions in error cases with exception handlers returning the status)

I am not sure this is gonna answer your question but you could throw a ResponseStatusException with the status code you need. Using it for the 200 would be strange though.

Related