Improve Your Spring REST API, Part I

After watching Jonathan Dahl’s presentation about API design from the Øredev conference last year, especially the parts about Smart Validations, it is apparent that you can do much more to help your client developers than just returning HTTP status code 500 – Internal Server Error, when a request to your REST API fails.

Spring WEB MVC

The Spring Web MVC framework is a great tool for creating restful web services. It takes care of request mapping, validation, serialization and de-serialization just to name a few. When it comes to error handling, the DefaultHandlerExceptionResolver makes a really good job behind the scenes for translating common exceptions to suitable HTTP status codes and adding response headers when applicable. If there is no resource mapped to the request URI, 404 – Not Found, is set as response code. If a HTTP method is not supported by a particular request URI, 405 – Method Not Allowed, is set as response code and the Allow response header is set to indicate which method(s) that can be used instead, and so on.

Unfortunately, things are not always that easy. What about when the developer receives a 400 – Bad Request? Obviously, there is something wrong with the request, but the response fails to tell the developer why it is not accepted. Take a look at the following controller method:

Even with the implementation available, it is impossible to unambiguously determine the cause of failure. Perhaps the de-serialization of the request body to the User object failed? Maybe the validation failed? Other possible causes of a 400 – Bad Request include erroneous request parameters, missing request headers, etc.

Inspired by Jonathan’s presentation, the idea is that the server will still respond with appropriate status codes, and the appropriate headers when applicable. Additionally, the response body should contain information that can assist the client developer, and in the format that the client requested (as specified by the Accept request header). For example, if the server expects a name and a valid email as part of the request, a suitable response could be a 400 – Bad Request with the following response body:

Solution

The @ExceptionHandler in conjunction with the @ResponseBody provide a simple solution to the problem:

The ErrorMessage is a simple helper class used for serialization:

Considerations

There is plenty of more information that may be added to the response that could be valuable for the REST API users. Some suggestions that come to mind are a default message text that could be presented to the end user, a custom error code for client developers or a link to relevant part of the application specific REST API doc, if it is published online.

Another question is how the error handling can be generalized to prevent the @ExceptionHandler implementation from being copied between all controllers in the project. Note, the example above includes just one of the potential error causes, it is likely that there are more similar implementations for other exceptions.

Side notes

JSR 303

The ability to use the @Valid annotation as part of a @RequestBody controller method argument was introduced in Spring 3.1. For completeness, the JAXB validation of the User class could be implemented as:

The Spring reference documentation provides configuration details.

XML

You may have noticed the @XmlRootElement annotation on the ErrorMessage class. It is a JAXB annotation required to make the XML serialization work. No additional dependency is required, since JAXB 2.0 was added to JDK 6u3.

JSON

A JSON message converter for serialization and deserialization is added automatically by Spring by just adding Jackson to the classpath. No additional setting is required, however you can tailor the behavior by adding Jackson annotation to your objects.

Dependencies

  • Spring 3.1.2.RELEASE
  • jackson-databind 2.0.5

References

Mattias Severson

Mattias is a senior software engineer specialized in backend architecture and development with experience of cloud based applications and scalable solutions. He is a clean code proponent who appreciates Agile methodologies and pragmatic Test Driven Development. Mattias has experience from many different environments, including everything between big international projects that last for years and solo, single day jobs. He is open-minded and curious about new technologies. Mattias believes in continuous improvement on a personal level as well as in the projects that he is working on. Additionally, Mattias is a frequent speaker at user groups, companies and conferences.

This Post Has 11 Comments

  1. Hi Mattias,

    Very nice post!

    I’m trying to make it work in my Spring MVC application and I made all these steps, but my request response is still comming as a web server error page. I’m not sure if it’s because of some diferent configuration, but I alredy made the same json validation response work in a webapp with Spring MVC 3.0.6.RELEASE before.

    Do you have your example code in a repository or a public zip file to check it out?

    Thanks in advance.
    Best regards.

    1. Awesome…This is really helpful…I was struggling with bad request for hrs before finding out the exact exception thrown from server.

  2. Thanks for this tutorial, please provide a simple zip source code.
    Thanks

    1. @Majid: Thank you for your comments. Unfortunately, I do not have any source code available apart from the snippets above, but there are several Spring MVC sample projects available online. For example, the Spring website provides several Guides such as the Building a RESTful Web Service.

  3. Thank you very much.

    It’s a great and clean way to figure out what’s going on on client’s requests and could possibly inspect it only on the server side without the need to let the client know which was the specific reason to suit my security concerns.

    Kind regards.

  4. First of all very nice article. I have a question you spoke about @notNull annotation to do simple validation. What about complex validation where shall i hadle it

    1. @Albert: Thank you.

      When I wrote the blog post, Spring supported the JSR 303 Bean Validation 1.0. More recently, Spring has also added support for the JSR 349 Bean Validation 1.1. Another useful source is to check the Hibernate Validator API. It is a reference implementation for the two JSRs and thus supports all bean validation constraints and some additional constraints. For your question, I think that you will find chapter 6 Creating custom constraints useful.

  5. There is suggestion that exception handling is expensive and should avoid to use it as flow control. May I know your opinion about that?

    1. @John: Depending on who you ask, you will get various answers and people tend to get religious about this matter. My personal opinion is that you should not use exception for flow control. That said, I am not worried about exception handling being expensive. For example if you implement a web app, the overhead of creating and handling an exception is negligible compared to the network latency. Likewise, if you are implementing an app that requires user interaction, the human reaction times is several orders of magnitude slower compared to the exception handling. My main motivation for not using exception for flow control is programming style, readability and maintainability of the code. Consequently, I would never use a try / catch block where an if statement is more appropriate. Sometimes it is quite obvious what to do, if you read the Javadoc of the ConcurrentModificationException you will find that:

      Fail-fast operations throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness

      .

Leave a Reply

Close Menu