Thursday, 20 December 2012

REST Web Service Spring Error Handling

The Spring framework provides excellent support for building REST web services in a service-oriented architecture (SOA), as I have demonstrated in a previous post, but what is not immediately obvious is how best to deal with errors. Instead of throwing raw exceptions to the client, one would prefer to return a well-formed response consisting of an appropriate HTTP status code and a meaningul response body containing a structured error message in the response form (JSON, XML, ...) requested by the client.

For example, assuming you have a basic REST endpoint such as:

 @RequestMapping(value = "/samples", method = {RequestMethod.GET})
 @ResponseBody
 public SampleList findAllSamples() throws SampleException {
  return new SampleList(service.findAllSamples());
 }

It is good practice in general to not let implementation exceptions leave the service tier, so you might use aspects to catch these and rethrow them as service exceptions.  The code below catches a ReferenceNotFoundException from the data access tier and throws a service exception with the reference number and setting the desired http status code.  Another good practice is to avoid sending free text error messages to a service client, and instead to send structured messages that can be dealt with or rendered as the client sees fit.

@Aspect
@Component("exceptionHandler")
public class ExceptionHandler {

   /**
    * Exception handler for ReferenceNotFoundExceptions
    * 
    * @param nfe the exception being handled
    */
   @AfterThrowing(pointcut = "execution (* com.sample.service.*.*(..))", 
                                              throwing = "nfe")
   public void handleNotFoundException(ReferenceNotFoundException nfe) {
      throw new SampleException(
         new ReferenceNotFoundError(nfe.getReference()), 
                               HttpStatus.NOT_FOUND);
   }


Now to map the service exception (SampleException) to a meaningful HTTP response using the Spring 3 @ExceptionHandler annotation:

   @ExceptionHandler(SampleException.class)
   @ResponseBody
   public SampleErrorList exceptionHandler(SampleException se,
                 HttpServletRequest req,
                 HttpServletResponse res) throws IOException {

      res.setStatus(se.getHttpStatus());

      return new SampleErrorList(se.getErrors());

   }
 

It is also possible to set the HTTP status code using an annotation, but in this example the exception determines this, so the handler sets it programmatically.

See here for a downloadable working sample.

REST Web Service Spring Error Handling