Thursday 26 April 2018

Handling Custom Status code in Response

Spring Boot Handling custom status codes for RESTful Services

This guide will help you implement custom error codes for effective exception/error handling for a REST API/Service with Spring Boot.

Without going into details of custom error codes and what are exceptions i will come to the point.
In case of REST we should always try ro send meaningful messages with proper error codes so that client is able to intercept the message and response accordingly.

inline are some status Codes and their description.

404 - RESOURCE NOT FOUND
400 - BAD REQUEST
401 - UNAUTHORIZED
415 - UNSUPPORTED TYPE - Representation not supported for the resource
500 - SERVER ERROR

Now lets think that you have an URL exposed something like.

https://SKPSHss:8080/sudent/{sudent_id}

Corresponding REST code :

 @GetMapping("/students/{id}")
 public Resource<Employee> getEmployee(@PathVariable long id) {
Optional<Employee> Employee = EmployeeRepository.findById(id);

if (!Employee.isPresent())
  throw new EmployeeNotFoundException("id-" + id);
  Resource<Employee> resource = new Resource<Employee>(Employee.get());
return resource;
  }

If any Employee is not present in the organization it will give the following response.

 {
  "timestamp": XXXXXX,
  "status": 500,
  "error": "Internal Server Error",
  "message": "id-1555",
  "path": "/employee/1555"
}

Now there was no internal server error as you were successfully able to intercept the request and process it but the response says its “Internal server error” and instead we should be sending 400 (Bad request).

Now comes the awaited point how to customize this response.
You can specify the Response Status for a specific exception along with the definition of the Exception with ‘@ResponseStatus’ annotation.

@ResponseStatus(HttpStatus.BAD_REQUEST)
public class EmployeeNotFound extends RuntimeException {
}

and you will get the following response.

{
  "timestamp": 1512714594153,
  "status": 400,
  "error": "Bad Reqiest",
  "message": "id-1555",
  "path": "/employee/1555"
}

Your client might not be interested in all the attributes that are being sent in response so you may need to customize the above response.

Let’s define a our own error response bean.

public class ErrorDetails {
  private String message;
  
  public ErrorDetails(String message) {
    super();
    this.message = message;
  }

To use ResponseDetails to return the error response, we need to define a ControllerAdvice as shown below.

@ControllerAdvice
@RestController
public class CustomizedResponseExceptionHandler extends ResponseEntityExceptionHandler {

  @ExceptionHandler(DataNotFound.class)
   public final ResponseEntity<ErrorDetails> handleDataNotFoundException(EmployeeNotFound ex, WebRequest request) {
    ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(),
        request.getDescription(false));
    return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
  }

new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST) - Create an error response object and return it with a specific Http Status.