Introduction

REST stands for Representational State Transfer and is based on the doctoral dissertation of Roy Fielding. In restful web service every thing considered to be resource. The resource may be text or XML or JSON or HTML or anything.

It Works on HTTP protocols.
  1. GET for reading resources
  2. PUT for creating resources
  3. POST for updating resources
  4. DELETE for deleting resources
We can define the paths to access particular resource by Annotations. Here some importanant annotations are there
  1. @PATH - to define path
  2. @POST - to handle HTTP POST request
  3. @GET - to handle HTTP GET request
  4. @PUT - to handle HTTP PUT request
  5. @DELETE - to handle HTTP DELETE request
  6. @Produces - to define output type
  7. @Consumes - to define input
  8. @PathParam - to get parameter values in post request.
  9. @QueryParam - to get parameter values in get request (in url).

Environment setup

1. required libraries (you can have later versions)
  • rasm-3.1.jar
  • jackson-core-asl-1.9.2.jar
  • jackson-jaxrs-1.9.2.jar
  • jackson-mapper-asl-1.9.2.jar
  • jackson-xc-1.9.2.jar
  • jersey-client-1.17.jar
  • jersey-core-1.17.jar
  • jersey-json-1.17.jar
  • jersey-server-1.17.jar
  • jersey-servlet-1.17.jar
  • jettison-1.1.jar
  • jsr311-api-1.1.1.jar
2.  download above libraries and add them to build path.
        Download Google GSON libray from here
Or download the project from the below link. It contains all jars which are required

web.xml configuration

<servlet>
   <servlet-name>Jersey REST Service</servlet-name>
   <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
   <init-param>
     <param-name>com.sun.jersey.config.property.packages</param-name>
     <param-value>com.sample.resources</param-value>
   </init-param>
   <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
   <servlet-name>Jersey REST Service</servlet-name>
   <url-pattern>/rest/*</url-pattern>
</servlet-mapping>

Case Study

Add below XML to web.xml. com.sun.jersey.spi.container.servlet.ServletContainer is a servlet which will handle all URL starts with "/rest/". This servlet must be loaded after starting of web server because this has to handle all REST requests. com.sample.resources is a package where all service classes exists.

GET Method

1. Create a Class named EmployeeResource (path = employee)
2. Create a method getEmployeeDetails with the following characteristics:
    Path: search
    Method: GET
    Query Parameter 1: version (Data Type = int, Default Value = 1)
    Query Parameter 2: employeeId (Data Type = int)
    Query Paramater 3: employeeName (Data Type = String)
    Produces: XML
3. Validations:
    Either employeeId or employeeName is mandatory. Validate if at least one of
    them is present else throw an exception.If the version is other than 1
    throw an Exception say “Invalid Version Number”
4. Create an Employee Object (Employee To should contain only 2 attributes
    employeeId and employeeName) hard code the employeeId and employeeName
5. Convert the Employee Object to XML using XStreams and send the response back.
6. In Case of Exception send the response as
    {
     "errorCode":-1,
     "errorMessage":"Exception Message"
    }

POST Method

1. Create a Class named EmployeeResource (path = employee)
2. Create a method maintainEmployeeDetails with the following characteristics:
     a. Path: maintain
     b. Method: POST
     c. Query Parameter 1: version (Data Type = int, Default Value = 1)
     d. FORM Parameter 1: inputData (Data Type =String)
     e. Consumes: XML
     f. Produces: XML
3. Validations:
     a.Check if the inputData is !=NULL and Length >0 else throw an exception.
     b.If the version is other than 1 throw an Exception say
     “Invalid Version Number”
4. The input Data will be of the Format
    {
        "employeeId":123456,
        "employeeName":"Sachin Tendulkar"
     }
5. Convert the input XML to Employee Object using XStream
6. Return an XML
      {
          "code":0,
          "message":"Employee Name parsed successfully"
       }
   Where Employee Name should be the one sent as Input.
7. In Case of Exception send the response as
      {
          "errorCode":-1,
          "errorMessage":"Exception Message"
       }

Building Service Class

package com.sample.resources;
import javax.ws.rs.*;

public class EmployeeResource {
/*
 * this class is for get and post employee detals by using
 * REST Full web services
 */
 /*
  * This method is for getting employee details by using employee details
  * and employeeName
  * @return String
  */
 public String getEmployeeDetails()
 { 
 }

 /*
  * This method is for maintain employee details by using employee details
  * and employeeName
  * @return String
  */
 public String maintainEmployeeDetails() 
 {
 }
}

@Path

We have to use @Path to make our example service web enabled. In below program the path was declared as "employee". This means it will handle all type of requests starts with "/employee"
package com.sample.resources;

import javax.ws.rs.*;
@Path("employee")
public class EmployeeResource {
/*
 * this class is for get and post employee detals by using
 * REST Full web services
 */
 /*
  * This method is for getting employee details by using employee details
  * and employeeName
  * @return String
  */
 public String getEmployeeDetails() {
 }

 /*
  * This method is for maintain employee details by using employee details
  * and employeeName
  * @return String
  */
 public String maintainEmployeeDetails() {
 }
}
In the same way add paths to methods also
package com.sample.resources;
import javax.ws.rs.*;

@Path("employee")
 public class EmployeeResource {
/*
 * this class is for get and post employee detals by using
 * REST Full web services
 */
 /*
  * This method is for getting employee details by using employee details
  * and employeeName
  * @return String
         * it handles http requests starts with "/employee/search" 
         * it handles http GET request
  */
         @GET
  @Path("search")
         public String getEmployeeDetails() {
         }

 /*
  * This method is for maintain employee details by using employee details
  * and employeeName
  * @return String
         * it handles http POST request
         * it handle http requests starts with "/employee/maintain" 
  */
         @POST
         @Path("maintain")
         public String maintainEmployeeDetails() {
         }
}

@GET & @POST

methods with @GET can handle get requests and methods with @POST can handle post requests.
package com.sample.resources;
import javax.ws.rs.*;

@Path("employee")
public class EmployeeResource {
/*
 * this class is for get and post employee detals by using
 * REST Full web services
 */
 /*
  * This method is for getting employee details by using employee details
  * and employeeName
  * @return String
         * it handles http requests starts with "/employee/search" 
         * it handles http GET request
  */
         @GET
         @Path("search")
         public String getEmployeeDetails() {
         }

 /*
  * This method is for maintain employee details by using employee details
  * and employeeName
  * @return String
         * it handles http POST request
         * it handle http requests starts with "/employee/maintain" 
  */
         @POST
         @Path("maintain")
         public String maintainEmployeeDetails()  {
         }
}

@Produces 

@Produces is to define output format of a method,  it may be XML or JSON or text or some other resource.
package com.sample.resources;
import javax.ws.rs.*;

@Path("employee")
public class EmployeeResource {
/*
 * this class is for get and post employee detals by using
 * REST Full web services
 */
 /*
  * This method is for getting employee details by using employee details
  * and employeeName
  * @return String
               * it handles http requests starts with "/employee/search" 
               * it handles http GET request
  */
        @GET
 @Path("search")
        @Produces("application/xml")
         public String getEmployeeDetails() {
         }

 /*
  * This method is for maintain employee details by using employee details
  * and employeeName
  * @return String
         * it handles http POST request
         * it handle http requests starts with "/employee/maintain" 
  */
         @POST
         @Path("maintain")
         @Produces("application/xml")
         public String maintainEmployeeDetails() {
         }
}

@QueryParam & @FormParam 

These annotations are to get particular parameter value from the input. @QueryParam is to get parameter values in URL (GET request). @FormParam is to get parameter values in the input of POST request (FORM data).
package com.sample.resources;
import javax.ws.rs.*;

@Path("employee")
 public class EmployeeResource {
/*
 * this class is for get and post employee detals by using
 * REST Full web services
 */
 /*
  * This method is for getting employee details by using employee details
  * and employeeName
  * @return String
               * it handles http requests starts with "/employee/search" 
               * it handles http GET request
  */
       @GET
       @Path("search")
       @Produces("application/xml")
       public String getEmployeeDetails(@QueryParam("employeeId") int employeeId,@QueryParam("employeeName") String employeeName) {
        }

 /*
  * This method is for maintain employee details by using employee details
  * and employeeName
  * @return String
               * it handles http POST request
               * it handle http requests starts with "/employee/maintain" 
  */
       @POST
       @Path("maintain")
       @Produces("application/xml")
       public String maintainEmployeeDetails(@FormParam("inputData") String inputData) {
       }
}

Versioning

One of the biggest maintenance headaches with Web Services in general revolves around maintaining different versions when you have multiple clients accessing your service. Here in REST web applications it is very easy to devide the code into versioning.In the below example if the system unable to find the query parameter then it will take 1 as default value for the parameter "version"
package com.sample.resources;
import javax.ws.rs.*;

@Path("employee")
public class EmployeeResource {
/*
 * this class is for get and post employee detals by using
 * REST Full web services
 */
 /*
  * This method is for getting employee details by using employee details
  * and employeeName
  * @return String
               * it handles http requests starts with "/employee/search" 
               * it handles http GET request
  */
      @GET
      @Path("search")
      @Produces("application/xml")
      public String getEmployeeDetails(@DefaultValue("1") @QueryParam("version") int version,@QueryParam("employeeId") int employeeId,@QueryParam("employeeName") String employeeName) {
      }

 /*
  * This method is for maintain employee details by using employee details
  * and employeeName
  * @return String
               * it handles http POST request
               * it handle http requests starts with "/employee/maintain" 
  */
      @POST
      @Path("maintain")
      @Produces("application/xml")
 public String maintainEmployeeDetails(@DefaultValue("1") @QueryParam("version") int version,@FormParam("inputData") String inputData) {
      }
}
Download the project and find all classes signatures

Java File For Handling JSON

This is Util class file. We can serialize and de-serialize java object by using GSON object.  Here generateJson function converts java object into JSON. generateToFromJson function converts JSON into Java Object
import com.google.gson.Gson;
import com.sample.model.ErrorDTO;
import com.sample.model.SuccessDTO;

public final class JsonGenerator {
/*
 * this class is for generating JSON    
 */
    
    /*
     * initialization of Gson class 
     */
    private static Gson gson = new Gson();
    
    /*
     * This class is for generating JSON from MODEL class
     * @param Object
     * @return String 
     */
    public static String generateJson(Object to) {
        return null == to ? "" : gson.toJson(to);
    }

    /*
     * Generates the transfer object from the given JSON using Google Gson.
     * 
     * @param String
     * @return transfer object
     */
    public static Object generateTOfromJson(String json, Class<?> class1) {
        return gson.fromJson(json, class1);
    }
    
    /*
     * this method is for generating error json
     * @param exception - Exception
     * @return String
     */
    public static String generateErrorJson(Exception exception) {
        
        ErrorDTO errorTO = new ErrorDTO();
        errorTO.setErrorCode(-1);
        errorTO.setErrorMessage(exception.getMessage());
        return generateJson(errorTO);
    }

    /*
     * Sets the error details to the ResponseDTO from the given Exception using Google Gson.
     * @param String
     * @return String
     */
    public static String generateSuccessJson(String message) {
        SuccessDTO successTO = new SuccessDTO();
        successTO.setCode(0);
        successTO.setMessage(message);
        return generateJson(successTO);
    }
}

Final Employee Resource Class

Here I have added the code of Serializing and de-serializing the object to web services methods
import javax.ws.rs.*;

import com.json.JsonGenerator;
import com.sample.model.Employee;

@Path("employee")
public class EmployeeResource {
/*
 * this class is for get and post employee detals by using
 * REST Full web services
 */
    
    /*
     * This method is for getting employee details by using employee details
     * and employeeName
     * @return String
     */
    @GET
    @Path("search")
    @Produces("application/json")
    public String getEmployeeDetails(
            @DefaultValue("1") @QueryParam("version") int version,
            @QueryParam("employeeId") int employeeId,
            @QueryParam("employeeName") String employeeName){
        String result = null;
        try {
            switch (version) {
            case 1:
                if (employeeName == null && employeeId == 0) {
                    throw new Exception("Invalid parameters");
                } else {
                    Employee emp = new Employee();
                    emp.setEmployeeId(employeeId);
                    emp.setEmployeeName(employeeName);
                    result = JsonGenerator.generateJson(emp);
                }
                break;
            default:
                throw new Exception("Invalid version number");
            }
        } catch (Exception e) {
            result = JsonGenerator.generateErrorJson(e);
        }
        return result;
    }

    /*
     * This method is for maintain employee details by using employee details
     * and employeeName
     * @return String
     */
    @POST
    @Path("maintain")
    @Produces("application/json")
    public String maintainEmployeeDetails(
            @DefaultValue("1") @QueryParam("version") int version,
            @FormParam("inputData") String inputData) {
        String result = null;
        try {
            switch (version) {
            case 1:
                if (inputData == null || inputData.length() <1) {
                    throw new Exception("Invalid data");
                } else {
                    Employee emp = (Employee)JsonGenerator.generateTOfromJson(inputData, Employee.class);
                    result=JsonGenerator.generateSuccessJson(emp.getEmployeeName()+" parsed successfully");
                }
                break;
            default:
                throw new Exception("Invalid version number");
            }
        } catch (Exception e) {
            result = JsonGenerator.generateErrorJson(e);
        }
        System.out.println("maintain "+result);
        return result;
    }
}

Testing

Input : http://localhost:8080/CaseStudyREST/rest/employee/search?employeeId=2
Output : 
{
   "employeeId":2
}

Input : http://localhost:8080/CaseStudyREST/rest/employee/search?employeeName=2
Output : 
{
   "employeeId":0,
   "employeeName":"2"
}

Input : http://localhost:8080/CaseStudyREST/rest/employee/maintain
Input Data :
{
  "employeeId":5,
  "employeeName":"sri"
}
Output :
{
   "code":0,
   "message":"sri parsed successfully"
}

0 comments:

Blogroll

Follow this blog by Email

Popular Posts