In my current company we are starting a new project that will be a REST API in Java, deployed in a servlet container like Tomcat. In my previous experience using REST frameworks like JAX-RS with Jersey, JBOSS REST Easy, Spring MVC I know what are some of the advantages of using a framework like those over writing directly the Servlets for processing the requests.
(Of course we know that the mentioned frameworks still use Servlets under the covers)
I am finding difficult to convince them. As they are proposing to write servlets thinking it is better for performance (which can be the case but I think the overhead of using one of those frameworks should be insignificant for a REST API).
Here are my reasons:
1) Less boilerplate and more concise code (which is easier to maintain and test). With a JAX-RS framework or SpringMVC you can define a REST resource very easily by writing methods with annotations indicating the PATH of the resource, the http method to use, query and url parameters, headers like encoding accepted, etc.
Example:
@GET @Path("/users") @Produces({MediaType.APPLICATION_JSON}) public UserList getUsers(@QueryParam("group") String group) { return userService.findUsers(group); }
With servlets you will need at least something like this:
Map the url for each servlet in web.xml (Which is not necessary in and above Servlet 3.0):
<servlet> <servlet-name>UsersServlet</servlet-name> <servlet-class>test.UsersServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>UsersServlet</servlet-name> <url-pattern>/users</url-pattern> </servlet-mapping>
Then inside the servlet class:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String group = request.getParameter("group"); response.setContentType("application/json"); PrintWriter out = response.getWriter(); JsonSerializer someJsonSerializer = new JsonSerializer(); String json = someJsonSerializer.serialize(userService.findUsers(group)); out.print(json); }
2) Adaptability. The mentioned frameworks allow you to easily add features to your application that otherwise you will need to do it manually, like using multiple media type inputs and outputs. For example making a service to return xml or json or any other depending on the accept header. Frameworks like SpringMVC and Jersey make it very easy to configure serializers/deserializers for your requests, responses.
3) REST best practices. Normally those frameworks are built over a solid understanding of the best practices to be followed by a REST API and are defined based on standards of the REST architecture which makes easier to build a solid and standard conforming application. In the other hand Servlets give you a so high level of freedom on how to process your requests/responses that it will be more difficult to realize that you are not being RESTfull at all.
Any other?
In a similar way, you can create REST applications using only the Servlet API. However, there are other APIs that are designed to create REST applications.
An HttpServlet is a natural, convenient way to implement RESTful web services for two main reasons. First, such servlets are close to the HTTP metal. For example, the HttpServlet class has methods such as doGet , doPost , doPut , and doDelete that match up with the HTTP verbs aligned with the CRUD operations.
Servlets are API which is simple and provides capabilities to write server side components. Rest provides higher level support for writing services which are denoted by using the concept of resource which represents a concept to be addressed while representation indicates the current state of resource.
REST is a software architecture “style”; Servlet is a server-side technology.
Let me play the devil's advocate with my answer.
First, you don't need to add the servlets to the web.xml file. Servlets 3.0 allow you to use annotations.
Second, there really is a significant performance hit with these frameworks. See these benchmarks
Third, you can use GSON within a servlet, which is faster than Jackson (used by default in Spring and Jersey). This gets you even more performance especially considering that performance is critical to your requirements.
Finally, if you are concerned about boilerplate, put that code that you wrote inside the servlet in some utility class and use it from multiple servlets. That beats carrying around a framework's huge load when you (like most people) would probably be using a small fraction of its functionality.
Several months ago I put a comment saying that I did support for the pure Servlet 3.0 solution against the use of REST MVC frameworks.
After months of usage, I confirm my choice!
I tried to install Jackson and others frameworks but it needs more work than writing the extra 5 lines of code and I don't have to cope with an extra software component to setup, learn, update...
Here is my working example:
package example; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.gson.Gson; /**@WebServlet(name = "booking", urlPatterns = { "/api/v1/booking" })*/ public class BookingWs extends javax.servlet.http.HttpServlet { public static final Logger LOGGER = LoggerFactory.getLogger(BookingWs.class); protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { // Used for JSON handling Gson gson = new Gson(); // De-serialize from request BookingRequest bRequest = gson.fromJson(request.getReader(), BookingRequest.class); // Do your business logic. BookingResponse bResponse = new BookingResponse(); bResponse.request = bRequest; bResponse.accepted = "bar".equalsIgnoreCase(bRequest.type); bResponse.reason = bResponse.accepted ? "Welcome" : "Only bar table booking left"; // Serialize and send response back; response.setContentType("application/json"); PrintWriter pw = response.getWriter(); gson.toJson(bResponse, pw); } catch (Throwable t) { response.setStatus(500); PrintWriter pw = response.getWriter(); pw.write("{\"error\":\"" + t.getLocalizedMessage() + "\"}"); } } } class BookingRequest{ String type; int seats; String name; long requiredTimestamp; } class BookingResponse{ BookingRequest request; boolean accepted; String reason; }
Maybe these frameworks have a feature you need absolutely, but for me it should be decisive enough to worth the hassle of extra libs.
As a French author Antoine de Saint Exupery said:
"Perfection is Achieved Not When There Is Nothing More to Add, But When There Is Nothing Left to Take Away".
I took away Jackson to get closer to it :-)
(Yes I have to admit, I used GSON, but it's a small jar, without any configuration needed).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With