Thursday, March 18, 2010

REST APIs in Java

Since my last post, I've been investigating ideas for how to go about implementing API calls using Java and Tomcat.  One of the big,new ideas for API construction is REST, which stands for Representative State Transfer.  The basic idea is that API-accessible resources have a specific URI endpoint, which can be drilled down further against by specifying an ID for a specific instance of a resource.  Parameters can be passed to allow filtering for objects meeting various criteria.  Additionally, the basic CRUD functionality (Create, Read, Update, Delete) required by a database-like interface can be mapped to the HTTP verbs (POST, GET, PUT, DELETE, respectively).  The results can come back as an XML document, or can also be JSON, or in the example in this article, just text/plain.

Some of the advantages of REST over SOAP for a web service are (these are some of my pragmatic reasons, there's lots of other pros and cons):

  • The amount of data transferred is smaller (minimal verbose XML)
  • It's more convenient to program against - not all languages fully support SOAP (e.g., Perl and Tcl)
  • It's faster to process, since there isn't all the XML to parse

Some of the dis-advantages of REST:
  • SOAP with WSDL is really straight-forward to program against if the language has good support (e.g. C#)
  • Not all languages support using all the HTTP verbs, such as PUT & Delete (e.g., FLEX)
In any case, my intention is to try a more REST-like implementation for the various API functions, and see what kind of performance I can get out of it.  In this article, I'm going to be implementing my first REST API call using Java.  I followed the instructions from coreservlets.com to get my development setup in place. Here are the steps I took to implement it (this is starting from scratch):

Part I: Setting up the Java Development Environment

1) Install the Java SE JDK 1.6 download from Sun (I used version 18).  I installed it to C:\Java32\jdk1.6.0_18, and set my JAVA_HOME enviroment appropriately.  Additionally, I added %JAVA_HOME%\bin directory to the front of the PATH variable. I went with the 32-bit version, since the 64-bit version isn't compatible with all the various tools I want to work with (such as Eclipse).

2) I used the version of Tomcat put together by coreservlets.com (tomcat-6.0.18-preconfigured.zip), but for the purposes of this exercise, I only took advantage of the fact that tomcat will be listening on port 80, instead of port 8080 (which the standard Tomcat listens on).  I installed it to C:\apache-tomcat-6.0.18 and set my CATALINA_HOME environment variable appropriately.
 
3) Download the J2EE version of Eclipse (I used eclipse-jee-galileo-SR2-win32.zip).  Since there's no installer, I unzipped the archive in my "Program Files (x86)" directory on my Windows 7 box.  I went with the 32-bit version (because that's all there is for Windows).   I used the default workspace for Eclipse's workspace.

4) Configure Eclipse to work with Tomcat.  The coreservlets tutorial has more info, but basically, you right-click in the Package Explorer, go to New->Other, click on the Server folder, and hit the next button.  You can then pick the specific version of Tomcat you are running (e.g., Tomcat v6.0 Server).  This will allow Eclipse to manage Tomcat by have it serve files out of an eclipse specified directory, restart Tomcat when necessary, etc.

Part II: Creating a Simple REST API call using Jersey

Now that the development environment is set up, now we'll put together the web services component.  This part of the project leverages the steps from article REST: Jersey configuration on Tomcat

1) In Eclipse, create a new dynamic web project (in Package Explorer, right click, and do New->Project, and in the Web folder, select "Dynamic Web Project".  I called my project "jaxrs-test".

2) Download Jersey.  Jersey is the reference implementation of JAX-RS put together by Sun.  I used version 1.1.5.1 for this experiment.  I copied the necessary files (asm-3.1.jar, jersey-server-1.1.5.1.jar,jersey-core-1.1.5.1.jar,jsr311-api-1.1.1.jar) into the project lib directory in my workspace (jaxrs-test\WebContent\WEB-INF\lib).  In order to get Eclipse to use the libraries for my project, I right clicked on jaxrs-test in the Package Explore, selected "Properties", and in the dialog selected "Java Build Path".  I selected the "Libraries" tab, and clicked the "Add Jars..." button and designated each of the libraries.

3) In order to use the servlet container in Tomcat to in conjunction with Jersey, I added the following to my web.xml under jaxrs-test\WebContent\WEB-INF:  (right before the </web-app> line:

<servlet>
    <servlet-name>RSTest</servlet-name>
    <servlet-class>
        com.sun.jersey.spi.container.servlet.ServletContainer
    </servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>RSTest</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

4) Now that all the setup is in place, we can start coding APIs.  Here is an example of how to make a very simple web service that just spits out the date and time.  Not very sexy, but it's a simple, non-database related web service that can be used for testing the speed of a really basic API call.

package jeffreyrothman.com;


import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import java.util.Date;
import java.text.SimpleDateFormat;

@Path ("/getTime")
public class TheTime {

    @GET
    @Produces ("text/plain")
    public String theTime() {
        Date now = new java.util.Date(); // get the current DateTime
        SimpleDateFormat dateformat =
            new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return dateformat.format(now);     }
}


5) Now we need to get Eclipse to publish this to the Tomcat server for us.  On the "Servers" tab under the development window, right-click on the Tomcat label, and select "Add and Remove".  Use the "Add" buttom to move the jaxrs-test project from the "Available" to the "Configured" side.  Then click "Finished".  The jaxrs-test label should show up under the Tomcat label. 

In the Package Explorer, right click on jaxrs-test and select "Run As".  Choose option "Run on Server" and select the Tomcat Instance.  A new window will pop up in Eclipse.  You'll need to add "getTime" to the URL to get it to work.  The time should now show up.  I can also use a web browser to call the web services, with URL http://localhost/jaxrs-test/getTime .  If you used the default version of Tomcat, you'll need to appened :8080 to localhost to get the page served up.

Congratulations!  You now have a simple web service.  Next time well look at expanding this example and bringing a database along for the ride.
 


Helpful Link Bibliography
A Tutorial on Installing and Using Jakarta Tomcat 6.0 for Servlet and JSP Development (useful for setting up the dev environment)
REST: Jersey configuration on Tomcat (using Jersey for JAX-RS)
Putting Java to REST (more examples using REST with JAX-RS)
[How-To] Print Date/Time in a Given Format in Java (how to format a date)
Jersey 1.1.5.1 User Guide