Wednesday, August 21, 2013

Restful code example using Spring MVC

In my previous blog, I talked about Restful webservices design. In this blog, I will provide sample code for the same using Spring MVC framework.

Spring MVC 3.x supports annotation based controllers, which are Restful in nature. 

Let us create a sample Spring web application for performing CRUD on User entity.


Creating project:

Create a Maven project with a archetype 'maven-archetype-webapp'.

pom.xml

<!-- version property -->
<properties>
    <spring.version>3.1.2.RELEASE</spring.version>
</properties>
<!-- servlet dependency for compilation -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>2.5</version>
    <type>jar</type> 
    <scope>compile</scope>
</dependency>

<!-- Spring MVC dependencies -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>${spring.version}</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>${spring.version}</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>${spring.version}</version>
</dependency>

<!-- Jackson dependency for JSON mapping-->
<dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-mapper-asl</artifactId>
    <version>1.9.13</version>
</dependency>


web.xml

<servlet>
    <servlet-name>mvc-dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>mvc-dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</context-param>
 
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>

The servlet-name is 'mvc-dispatcher'. So we need a context xml with the name mvc-dispatcher-servlet.xml

mvc-dispatcher-servlet.xml


<beans xmlns="http://www.springframework.org/schema/beans"  
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
          xmlns:mvc="http://www.springframework.org/schema/mvc"  
          xmlns:context="http://www.springframework.org/schema/context" 
          xmlns:util="http://www.springframework.org/schema/util"  
          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 
                              http://www.springframework.org/schema/util 
                              http://www.springframework.org/schema/util/spring-util.xsd">   

          <context:component-scan base-package="com.myorg" />
 
          <mvc:annotation-driven/>
  
          <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
                <property name="messageConverters">
                <util:list id="beanList">
                    <ref bean="stringHttpMessageConverter"/>        
                </util:list>
                </property>
          </bean>
   
          <bean id="stringHttpMessageConverter" 
                              class="org.springframework.http.converter.StringHttpMessageConverter"/>
 
          
          <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
                 <property name="mediaTypes">
                 <map>
                    <entry key="html" value="text/html"/>
                    <entry key="json" value="application/json"/>
                 </map>
                 </property>
                 <property name="viewResolvers">
                      <list>
                      <bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
                      <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                          <property name="prefix" value="/WEB-INF/jsp/"/>
                          <property name="suffix" value=".jsp"/>
                      </bean>
                      </list>
                 </property>
                 <property name="defaultViews">
                    <list>
                        <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
                    </list>
                 </property>
         </bean>
</beans>

Things to know:

  • The namespaces in the beans element are very important as the spring container validates this xml against the xsd.
  • Every xmlns attribute should have a corresponding entry in the xsi:schemaLocation attribute. Here we have used mvc, context, util prefixes.
  • 'component-scan' element tells the spring container to look for com.myorg package for annotated controllers.
  • 'mvc:annotation-driven' tells the spring container that we are using annotated controllers.
  • InternalResourceViewResolver is used to indicate that the views are present in '/WEB-INF/view/' folder with jsp extension.
  • The ContentNegotiatingViewResolver is used to produce the correct format of response from our controllers. For Restful webservices, we will need response formats like JSON,html,xml etc. 
  • MappingJacksonJsonView is used to convert Java POJO to JSON format.


User POJO:

public class User implements Serializable{
    private static final long serialVersionUID = 10008L;
 
    private String firstName;
    private String lastName;
    private long userId;
 
    public User(String _first, String _last){
      this.firstName = _first;
      this.lastName  = _last;
    }
 
    public User(){  
    }
    
    //Setters and Getters
}  

User Service:

The service is a trivial implementation for brevity.


public interface UserService {
    public User createUser(User user) throws UserCreateException;
    public User getUser(String userId) throws UserNotFoundException;
    public void updateUser(User user) throws UserNotFoundException;
    public void deleteUser(String userId) throws UserNotFoundException;
}

Implementation is provided below. Note the @service annotation which is then injected into the controller using autowiring.


@Service
public class UserServiceImpl implements UserService{
    public User createUser(User user) throws UserCreateException{
       //implement here
       user.setUserId(111);
       return user;
    }

    public User getUser(String userId) throws UserNotFoundException{
       User user = new User();
       if(userId == null){
           throw new UserNotFoundException("Invalid User Id");
       }
       user.setFirstName("John");
       user.setLastName("Howard");
       return user;
    }

    public void updateUser(User user) throws UserNotFoundException{
       //implement here
    }

    public void deleteUser(String userId) throws UserNotFoundException{
      //implement here
    }
}

Exception classes


public class ServiceException extends Exception{
     private static final long serialVersionUID = 1L;
 
     public ServiceException(String _msg){
         super(_msg);
     }
}

public class AuthenticationException extends ServiceException{
    private static final long serialVersionUID = 1L;
  
    public AuthenticationException(String _msg){
        super(_msg);
    } 
}

public class UserCreateException extends ServiceException{
    private static final long serialVersionUID = 1L;
 
    public UserCreateException(String _msg){
        super(_msg);
    }
}
  
public class UserNotFoundException extends ServiceException{
    private static final long serialVersionUID = 1L;
 
    public UserNotFoundException(String _msg){
       super(_msg);
    }
}


UserController:


@Controller
public class UserController extends AbstractController{
 
    @Autowired
    private UserService userService;
 
    @RequestMapping(value="/restexample/users/user",method=RequestMethod.POST,
                    produces="application/json")
    @ResponseBody
    public User createUser(@RequestBody String body, HttpServletRequest _request) 
                           throws UserCreateException,AuthenticationException{
  
         authenticate(_request, "createUser");
  
         String firstName = _request.getParameter("firstName");
         String lastName = _request.getParameter("lastName");

         User user = new User(firstName,lastName);

         user = userService.createUser(user);

         return user;
    }
 
    /*Invoked depending on accept header*/
 
    @RequestMapping(value="/restexample/users/user/{userId}",method=RequestMethod.GET,
                    produces="application/json")   
    @ResponseBody
    public User getUser(@PathVariable String userId,HttpServletRequest _request) 
                        throws UserNotFoundException,AuthenticationException{
   
        authenticate(_request, "getUser");
        return userService.getUser(userId);
    }
 
    @RequestMapping(value="/restexample/users/user/{userId}",method=RequestMethod.GET)   
    @ResponseBody
    public String getUserAsHTML(@PathVariable String userId,HttpServletRequest _request) 
                               throws UserNotFoundException,AuthenticationException{

        authenticate(_request, "getUser");
        User user =  userService.getUser(userId);

        StringBuilder builder = new StringBuilder();
        builder.append("FirstName: ").append(user.getFirstName());
        builder.append("LastName: ").append(user.getLastName());
    
        return builder.toString();
    }
 
    @RequestMapping(value="/restexample/users/user/{userId}",method=RequestMethod.PUT)
    @ResponseBody
    public String updateUser(@PathVariable String userId,@RequestBody String body, 
                                  HttpServletRequest _request) 
                           throws UserNotFoundException,AuthenticationException{
   
        authenticate(_request, "updateUser");
        long userIdVal = convertStringToLong(userId);

        if(userIdVal < 1){
             throw new UserNotFoundException("Not a valid User Id: "+userId);
        }

        String firstName = _request.getParameter("firstName");
        String lastName = _request.getParameter("lastName");

        User user = new User(firstName,lastName);
        user.setUserId(userIdVal);

        userService.updateUser(user);
        return "success";
    }
 
    @RequestMapping(value="/restexample/users/user/{userId}",method=RequestMethod.DELETE)
    @ResponseBody
    public String deleteUser(@PathVariable String userId,@RequestBody String body, 
                                  HttpServletRequest _request) 
                           throws UserNotFoundException,AuthenticationException{

        authenticate(_request, "createUser");

        User user = new User();

        userService.deleteUser(userId);
        return "success";
    }
 
    public void authenticate(HttpServletRequest _request, String _serviceName) 
                             throws AuthenticationException{

        String hashKey = _request.getHeader("hashKey");
        boolean valid = true;
        //validate hashkey
        if(!valid){
             throw new AuthenticationException(_serviceName);
        }
    }
}


AbstractController:



public abstract class AbstractController {
 
  private final String USER_NOT_FOUND_ERROR_CODE = "1002";

  private final String USER_NOT_FOUND_ERROR_DESC = "The provided user cannot be found.";

  private final String AUTHENTICATION_ERROR_CODE = "1003";

  private final String AUTHENTICATION_ERROR_DESC = "You are not authorized to access this service.";

  private final String USER_CREATION_ERROR_CODE = "1001";

  private final String USER_CREATION_ERROR_DESC = "User creation failed. ";

  private final String UKNOWN_ERROR_CODE = "1000";

  private final String UKNOWN_ERROR_DESC = "An unknown error has occurred";

 
  @ExceptionHandler(ServiceException.class)
  @ResponseBody
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  public RestError handleServiceException(ServiceException ex, HttpServletResponse _request){
      RestError error = new RestError();

      if(ex instanceof AuthenticationException){
        error.setErrorCode(AUTHENTICATION_ERROR_CODE);
        error.setErrrorDesc(AUTHENTICATION_ERROR_DESC);
      }
      else if(ex instanceof UserCreateException){
        error.setErrorCode(USER_CREATION_ERROR_CODE);
        error.setErrrorDesc(USER_CREATION_ERROR_DESC);
      }
      else if(ex instanceof UserNotFoundException){
        error.setErrorCode(USER_NOT_FOUND_ERROR_CODE);
        error.setErrrorDesc(USER_NOT_FOUND_ERROR_DESC);
      }
      else {
        error.setErrorCode(UKNOWN_ERROR_CODE);
        error.setErrrorDesc(UKNOWN_ERROR_DESC);
      }
      return error;
  }
}

RestError:


public class RestError implements Serializable{
    private static final long serialVersionUID = 198L;
 
    private String errorCode;
    private String errrorDesc;
 
    //Setters and getters
}

Things to know:


  • The controller extends from AbstractController which is explained later.
  • @RequestMapping can be used to map the Rest URI to the method. We can add parameters to the URI like {userId}
  • The parameters are mapped to variables through PathVariable
  • The method can declare what media type it is consuming/producing. For eg, produces="application/json"
  • The method can also declare what request type it is accepting through method=RequestMethod.POST/PUT/GET etc.
  • The accept header set by the client will be used to determine the method to be invoked.
  • The method can declare that it is returning a response in the Response body through @ResponseBody.
  • If the response type is a custom object like 'User', Jakson Mapping view will convert it to JSON format if required.
  • The authentication performed here is simple authentication by using a secret hash key (which is preagreed by client/server).This hash key is sent across in the request header. 
  • The same URI can be mapped to send across different response formats.
  • The getUserAsHTML() and getUser() map to same URI. However, getUserAsHTML() returns html content (the method can return a div content) whereas getUser() returns JSON content.


Handling exceptions:

The @ExceptionHandler annotation could be used to handle the exceptions. However, Spring requires every controller to have its own @ExceptionHandler annotated method.

To overcome this, we can have an abstract controller and have the exception handling at a common place. We can have different methods for each type of exception, or as in the example, we can handle the super exception class which is ServiceException and then handle individually.
If you are using Spring 3.2, you can use the @controlleradvice annotation and use any class for exception handling.

Rest Services generally should provide meaningful error messages and custom error codes when there is an error. At the same time, it should also prevent the internal exception hierarchy from reaching the client. In our example, the RestError object will which is returned by the exception handler will be converted to JSON format and returned back to the client.

Note that the error messages could be enumerated for better clarity.



Testing:

I have used Soap Client for testing. We can set the request type POST/GET etc and aslo the accept headers (application/json etc)

Following is the sample responses for a few requests:


Error Response:



HTTP response:
HTTP/1.1 400 Bad Request
Server: Apache-Coyote/1.1
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Tue, 20 Aug 2013 11:26:01 GMT
Connection: close

{"errorCode":"1003","errrorDesc":"You are not authorized to access this service. "}

JSON:
{
   "errorCode": "1003",
   "errrorDesc": "You are not authorized to access this service. "
}

Success response as JSON:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: application/json
Transfer-Encoding: chunked
Date: Tue, 20 Aug 2013 11:58:09 GMT

{"firstName":"John","lastName":"Howard","userId":111}

Sunday, August 11, 2013

Restful Webservices

This article is about Restful webservices and some thoughts on its design/architecture.

REST stands for Representative State Transfer. Restful architecture is resource oriented. The services expose a set of resources to the client and client can perform a set of operations on the resources which modify the state of the resource.

Design:

Restful webservices design requires a paradigm shift in the way we think about designing services. In the SOAP world, it was all about operations. So we used to think, what will this webservice "DO". But that is something which we should not do in Restful. 

Let's take for example an order entry application. In the SOAP world, we would think about services like createOrder, updateOrder, addLineItems etc. To design the same in Restful world, we need to identify all the resources in the application which the client cares about. These resources need not necessarily have a one to one mapping to the underlying schema. It is just the resources which matter to the client.

In our example, the resources could be Order, LineItem, Customer etc. We also need to establish a hierarchy amongest these resources for eg.,  Customer -> Order  -> LineItem. 


How to identify the resources?


The resources are identified by using URI. The URI should be something like a directory structure listing so that the client will not have  too much of a trouble to guess the URI. The URI could also embed identifiers to pin point to a particular resource. For eg, an order ID, a customer ID etc.

In our example, the URI to identify an order with an order ID of 1000 for a customer Paul could be something like: http://www.orderentryapp/resources/customers/customer/paul/orders/order/1000/

Note that we could easily guess the hierarchy and drill down to the particular order. Removing /order/1000 will return an URI:
http://www.orderentryapp/resources/customers/customer/paul/orders/

The above URI will identify all the orders ordered by paul.


How to operate on Resources?

So, how can the client operate on these resources. Restful relies on HTTP protocol and uses the standard GET,PUT,POST,DELETE operations.

GET - Retrieve a resource (eg., It retrieves the order with order ID 1000)

PUT - Create/update a resource (completely replace existing) when you know the URI which will be created/updated

POST - Create a resource when you do not know the URI which will be created

DELETE - Delete a resource. However, this will require proper authentication of the client to prevent unholy deletes.

HEAD - Identical to GET except that the server MUST NOT return a message-body in the response. HEAD should be used to return meta data about the resource returned by GET. Clients can cache the results of HEAD. For eg, HEAD could be used to check if a resource exists or the last modified date
  
For PUT/POST - The client can send parameters as HTTP post parameters to create/update the resource.

Now, there is an argument over usage of PUT vs POST. 

PUT requires the operation to be idempotent, while POST does not. 
i.e, multiple invokes to PUT the same resource should result in the same outcome.

Let me explain this in more detail:
The URI in consideration is: http://www.orderentryapp/resources/customers/customer/paul/orders/order/1000

Now a PUT request to the above URI, should create a new order with an ID of 1000. If an order already exists with ID of 1000, the resource should get replaced with the data provided in this request. So, no matter how many times we invoke PUT for ID of 1000, the outcome will always be an order with ID 1000. That is idempotency.

Now the definition of POST says that, POST should be used to create a child resource as well as the URI. i.e, the client is not aware of the URI being generated. 

1. Usecase for POST:

Client says "Create an order for me and return me back an ID which I could use in further requests".

So, a POST to http://www.orderentryapp/resources/customers/customer/paul/orders/order will generate an Order with ID (say) 1000 and it will also create an URI
http://www.orderentryapp/resources/customers/customer/paul/orders/order/1000.
  
Subsequent PUTs to the above URI will update the order with ID 1000. So, POST could be used to create orders when the server will generate unique IDs rather than client specifying the IDs.

2. Usecase for PUT:
Client says "Create an order for me with ID 1000 and I will use the ID 1000 for further requests". Note that here, 1000 need not be the primary key on the server side. That detail is hidden from the client. The server might generate its own primary Id and correlate it to 1000. All that the client cares is that, it should be able to get/update using that ID.

How to handle errors?

Exception scenarios could be handled by returning HTTP error codes like 400,404, 403 etc.


What are the Response formats?

RESTful services can return XML, JSON etc which is driven by the HTTP accept header.

Also, an interesting point to note is that we can also return URIs in the response. Let's say after a POST to create a new order, instead of returning an ID, we can return the new URI, which could be used by the client for further GET/PUT requests. This can be done by returning the URI in the location header. For eg., Location: /order/1000


SOAP or REST?

Now the final question. Should I use SOAP or REST? The answer really depends on the use case. Ask yourselves these questions:
 1. Am I able to identify resources in my system? 
 2. What is the nature of service expected by the clients of my service? 
 3. Is my system an operation engine or a resource driven system? For eg, systems like billing engine, or  tax calculation engine are more of service driven which may not fit the Restful bill.

Note that Restful clients are extremely simple to build when compared to SOAP clients which involve complicated bindings and infrastructure plumbing code. A well designed SOA application can have a combination of REST as well as SOAP based services.






Sunday, August 4, 2013

The Beginning.....

I wanted to blog on technical stuff since long and finally it has taken off.

My primary focus will be on Java and J2EE architecture, design patterns and SOA. The blog content could be my thoughts on design and architecture  or could also be a step by step tutorial stuff.

I will also try to post a few on AI which is my personal favorite topic, but I'm still a novice in this area. AI being a vast field with so many disciplines in it, my posts on AI will be purely basic and rudimentary.