Recently I had an opportunity to use two different REST libraries to write client side code for consuming REST web services. The libraries were Spring RestTemplate (spring-web, 4.3.10.RELEASE) and Jersey Client (jersey-client, 1.18). Although the latter is an older version, it was much easier to use it. My goals were very simple and specifically the following:
- Invoke different HTTP methods on the service
- Setup Basic Authentication on the client code.
- Log request and response.
- Handle the HTTP error responses.
- Write test cases which mock the server.
Spring provides RestTemplate API to invoke various HTTP methods on a REST Web Service. Although there are methods dedicated to most HTTP method such as getForObject GET, postForObjectPOST, PUT etc., the methods don't provide full control over what is to be sent out. So you have to rely on the generic methods such as exchange or execute.When using these method one has to supply parameter such as HttpEntity even when you don't want to send any and this ambiguously named class is used to setup HTTP headers on the request (some examples on this thread).
The API provides ways to build the URI dynamically with simple templating for path param and HTTP parameters. However, the approach is clunky as there are two approaches to achieve data binding on the URI template. One is using a map which would be used to replace the key in the URI template. Second is by passing var args to methods in the same sequence as the placeholders appear on the URI templates. Both the approaches require that HTTP parameter name is mentioned on the URI template. Either of the approaches can lead to a messy code where it can be difficult to track on which parameter which value is being set.You can see the examples on this thread. On the other hand, Jersey client provides a fluent API to implement the client code. The API is very intuitive and doesn't require any specific order in which one must provide data for the URI template.The query and path parameters can be easily supplied using methods on the WebResource API. Some more examples on this page.
Setting basic authentication using either of the libraries wasn't difficult. Spring requires us to setup an interceptor on the RestTemplate instance whereas Jersey requires adding filter class. Both the libraries provide built-in implementations which can be extended if required. Spring provides BasicAuthorizationInterceptor and Jersey provides HTTPBasicAuthFilter.
Logging request and response is an important feature for investigation. Like basic authentication, this feature is to be implemented using an interceptor in Spring and a filter in Jersey. Jersey gives a very handy implementation of such as filter called LoggingFilter which can help in logging all kinds of incoming and outgoing traffic. Spring requires you to implement your own interceptor. But that's not enough, you also need to configure the RestTemplate instance to use BufferingClientRequestFactory which helps in reading the response from input stream twice - once for logging and another for application code. Sample implementation can be seen here. The sample implementation of LoggingFilter in Jersey has this aspect built-in. So Jersey gives us a headstart.
Spring RestTemplate approach towards handling HTTP status codes which are not in the 2xx range isn't user-friendly in my opinion. Spring will throw an exception - HttpClientErrorException or HttpServerErrorException if it doesn't see successful response. This forces developer to implement a try-catch block to handle the error or register an error handler with RestTemplate. Whereas Jersey's approach is to hand over the ClientResponse instance and it is up to the developer to decide how to treat the response i.e. more freedom.
Finally, let's get into writing test cases. The first thing that is crucial here is to mock server response. Spring is the clear winner here. It provides a very handy set of APIs to mock a REST web service response which allows us to focus on testing the business logic. Have a look at MockRestServiceServer.With Jersey, you have to rely on mocking APIs like Mockito to mock Jersey client APIs which is very distracting and boring.
Considering how easy I found using Jersey to write code that consumes a REST web service, I would say Jersey win in comparison.Spring framework is open enough give us libraries which lets us use Jersey along with Spring. So even if you are working on a Spring based application you can safely use Jersey for your JAX-RS needs.
Disclaimer: I am writing this blog to share my experience in a fairly simple use case. So YMMV. Spring lovers may disagree with me. There are other libraries which such as RESTEasy which I haven't explored. You may share your experience/opinion so that I can learn from your experience too.