How to code REST API with JAVA and Spring 3.0

In 10 easy step I show how to write simple server side code to handle REST Request.
As you know, REST specification describe using POST, GET, PUT and DELETE method  for CRUD operations.
In this article we will start with simplest user case – get a resource back to client as JSON object.
JSON became a de factor standard for AJAX base application.

I assume you understand annotation-based model of spring MVC.
Spring 3 brings full-scale REST support in Spring MVC, including Spring MVC controllers that respond
to REST-style URLs with XML, JSON, RSS, or any other appropriate response.

I will be using MyEclipde IDE for the demo but it does not matter really what IDE you are using.

  1. Create a new Java web project in Eclipse
  2. Add latest Spring 3.0.5 RELEASE libraries to project classpath. In our case WEB-INF/lib
  3. We will also need Jackson JSON processing libraries from http://jackson.codehaus.org/ in classpath. Make sure you got core and mapper jar files.   Here is a snapshot of my machine libraries.
  4. Libraries for REST API and spring 3

    Libraries for REST API with Spring 3

  5. Configure servlet dispatcher to handle our request in web.xml
  6. <!-- Handles all requests into the application -->
    	<servlet>
    		<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
    		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    		<init-param>
    			<param-name>contextConfigLocation</param-name>
    			<param-value>
    				/WEB-INF/servlet-context.xml
    			</param-value>
    		</init-param>
    		<load-on-startup>1</load-on-startup>
    	</servlet>
    
    	<servlet-mapping>
    		<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
    		<url-pattern>/</url-pattern>
    	</servlet-mapping>

  7. Create a servlet context file servlet-context.xml. Here we have to tell Spring to use annotation driven features and register controllers with @Controller annotation. <annotation-driven> enabled all annotation-driven features.
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xmlns:context="http://www.springframework.org/schema/context"
    	xmlns:mvc="http://www.springframework.org/schema/mvc"
    	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
    		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    
    <!-- handling static content-->
    <mvc:resources mapping="/static/**" location="/static/" /> 
                     
    	<!-- Scans the classpath of this application for @Components to deploy as beans -->
    <context:component-scan base-package="org.myapp.controller" />
    
    	<!-- Configures the @Controller programming model -->
    	<mvc:annotation-driven />
    	
    
    </beans>	

    <context:component-scan> entry will allow spring to pick up and register @Controller annotated class as bean inside package you specified. This will greatly simplify our configuration.
  8. Write controller. RequestMapping on class level will bind this servlet to respond to any call to /accesstoken url. On method level @RequestMapping helps specify which method will be called depending on HTTP Request methods.
    package org.myapp.controller;
    import java.util.Random;
    
    import javax.servlet.http.HttpServletResponse;
    
    
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.HttpStatus;
    import org.springframework.stereotype.Controller;
    import org.springframework.validation.BindException;
    import org.springframework.validation.BindingResult;
    import org.springframework.web.bind.annotation.*;
    @Controller
    @RequestMapping("/accesstoken")
    public class accesstokenController {
            @RequestMapping(method=RequestMethod.POST,headers = {"Accept=text/xml, application/json"})
    		@ResponseStatus(HttpStatus.CREATED) //
    		public @ResponseBody 
    		Accesstoken createAccessToken(HttpServletResponse response)
    		throws BindException {
    			
    			Random r =	new Random();
    			Accesstoken accessToken=new Accesstoken(r.nextLong(),"test value");
    			return accessToken;
    		}
    		
    	}
    
    

    @RequestMapping(method=RequestMethod.POST) will be invoked on post request. We annotate returning Java object with @ResponceBody. It indicates that the HTTP message converter mechanism should take over and transform the returned object into whatever form that the client needs. This will tell spring to look into HTTP Accept header and choose appropriate converter. If we supply Accept header with application/json value then JSON MappingJacksonHttpMessageConverter converter will be invoked.
    Only caveat you have to be sure Jackson JSON library are in the classpath. Access token is a simple bean I am using for demo purposes. In real application there should be call to service method of some facade bean using Dependency injection.
  9. Test using  html or javascript or curl. Make sure your POST request have Accept header set to “application/json”. with html and dojo library
  10. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    <html dir="ltr">
        
        
        <head>
            <style type="text/css">
                body, html { font-family:helvetica,arial,sans-serif; font-size:90%; }
            </style>
            <script src="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/dojo.xd.js"
            djConfig="parseOnLoad: true">
            </script>
            <script type="text/javascript">
                dojo.require("dijit.form.Button");
    
                function sendText() {
                    var button = dijit.byId("submitButton2");
    
                    dojo.connect(button, "onClick", function(event) {
                        //The parameters to pass to xhrPost, the message, and the url to send it to
                        //Also, how to handle the return and callbacks.
                        var xhrArgs = {
                            
                            url: "/blog/accesstoken",
                            postData: "Some random text",
                            
    						contentType: "application/json",
    						headers: {
    						 "Accept": "application/json",
    						},
    						handleAs: 'json',
    						
    						
                            load: function(data) {
                                dojo.byId("response2").innerHTML = "Message posted.  Access token id="+data.id;
                            },
                            error: function(error) {
                                //We'll 404 in the demo, but that's okay.  We don't have a 'postIt' service on the
                                //docs server.
                                dojo.byId("response2").innerHTML = "Message posted.";
                            }
                        }
                        dojo.byId("response2").innerHTML = "Message being sent..."
                        //Call the asynchronous xhrPost
                        var deferred = dojo.xhrPost(xhrArgs);
                    });
                }
                dojo.addOnLoad(sendText);
            </script>
            <link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dijit/themes/claro/claro.css"
            />
        </head>
        
        <body class=" claro ">
            <b>
                Push the button to POST some text.
            </b>
            <br>
            <br>
            <button dojoType="dijit.form.Button" id="submitButton2">
                Send it!
            </button>
            <br>
            <br>
            <b>
                Result
            </b>
            <div id="response2">
            </div>
            <!-- NOTE: the following script tag is not intended for usage in real
            world!! it is part of the CodeGlass and you should just remove it when
            you use the code -->
            <script type="text/javascript">
                dojo.addOnLoad(function() {
                    if (document.pub) {
                        document.pub();
                    }
                });
            </script>
        </body>
    
    </html>

    or curl
    curl -i -H "Accept: application/json" -d param=10 http://localhost:808/blog/accesstoken
    
    HTTP/1.1 201 Created
    Server: Apache-Coyote/1.1
    Content-Type: application/json
    Transfer-Encoding: chunked
    Date: Fri, 07 Jan 2011 17:48:29 GMT
    
    {"id":5767256863843874573,"token":"test value"}

You should write a test case with junit to make sure everything still working as you star add to this code.
That basically it. There is a lot of different @RequestMapping parameters, but simple idea is
than Spring 3 greatly simplify REST/Ajax development.
I would recommend latest Spring in Action, Third Edition which cover Spring 3 in great details.
By the way, I found that reading Mannings E-books pdf files on my Kindle is quite good experience. All you have to do is to rotate E-book into landscape position. Not as good as kindle format, but quite readable.

Submit a Comment

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>