Wednesday, June 3, 2015

Restful API using Java/Jersey and MongoDB


About this post

In this example I have created a REST web-service which stores some data about the books in the MongoDB database and will retrieve those data in the JSON format. I have used Openshift cloud platform to host the web application. 


Project structure

Project structure






ServletContainer.class


java.lang.Object
  extended by javax.servlet.GenericServlet
      extended by javax.servlet.http.HttpServlet
          extended by com.sun.jersey.spi.container.servlet.ServletContainer

It is a Servlet Filter for deploying root resource classes.



MongoDB Book record snapshot


Screenshot from RockMongo


Each data of the book is saved as a JSON document in the database. 




web.xml





RESTWebApp  
   
  jersey-serlvet  
    
         com.sun.jersey.spi.container.servlet.ServletContainer  
          
 1  
    
   
  jersey-serlvet  
  /api/*  
   

Here we are redirecting urls with pattern "api/*" to jersey-serlvet. 

Libraries needed

 The RESTFul Framework is provided by jersey-bundle.jar and asm.jar. And also we need mongo-java-driver.jar to connect to the MongoDB database. You can get it by simply adding  Maven dependencies under the <dependencies> tag. 


   asm
   asm-all
   3.3.1
  
  
   com.sun.jersey
   jersey-bundle
   1.14
  
  
   org.mongodb
   mongo-java-driver
   2.11.4
  

Create Java Bean - Books.java

package raspberry.rest.demo;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "Books")  
public class Books {

 private String title;  
 private String description;  
 private String year; 
 private String by; 
 private long likes;
 
 public void setTitle(String String){
  this.title = String;
 }
 public void setDescription(String String){
  this.description = String;
 }
 
 public void setLikes(long String){
  this.likes = String;
 }
 public void setYear(String String){
  this.year = String;
 }
 public void setBy(String String){
  this.by = String;
 }
 
 @XmlElement  
 public String getTitle(){
  return this.title ;
 }
 @XmlElement  
 public String getDescription(){
  return this.description;
 }
 @XmlElement  
 public long getLikes(){
  return this.likes;
 }
 @XmlElement  
 public String getYear(){
  return this.year ;
 }
 @XmlElement  
 public String getBy(){
  return this.by;
 }
}

MongoDBSingleton.java


This is a Singleton class which holds the MongoDB instance. We can access the db by calling MongoDBSingleton.getTestdb() . 



package raspberry.rest.demo;

import java.net.UnknownHostException;

import com.mongodb.DB;
import com.mongodb.MongoClient;

public class MongoDBSingleton {

 private static MongoDBSingleton mDbSingleton;
 
 private static MongoClient mongoClient;
    
 private static DB db ;
 
 
 private static final String dbHost = "dbHost here";
 private static final int dbPort = 27017;
 private static final String dbName = "dbName here";
 private static final String dbUser = "dbUser here";
 private static final String dbPassword = "dbPassword here";

 private MongoDBSingleton(){};
 
 public static MongoDBSingleton getInstance(){
  if(mDbSingleton == null){
   mDbSingleton = new MongoDBSingleton();
  }
  return mDbSingleton;
 } 
 
 public DB getTestdb(){
  if(mongoClient == null){
   try {
    mongoClient = new MongoClient(dbHost , dbPort);
   } catch (UnknownHostException e) {
    return null;
   }
  }
  if(db == null)
   db = mongoClient.getDB(dbName);
  if(!db.isAuthenticated()){
   boolean auth = db.authenticate(dbUser, dbPassword.toCharArray());
  }
  return db;
 }
}


WebController.java


This class handles all requests coming to the jersey-serlvet and produce the output data. This class uses the following JAX annotations.

@Path - Identifies the URI path that a resource class or class method will serve requests for.

@GET - Indicates that the annotated method responds to HTTP GET requests

@Produces - Defines the media type(s) that the methods of a resource class or javax.ws.rs.ext.MessageBodyWriter can produce.


package raspberry.rest.demo;

import java.util.ArrayList;
import java.util.List;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
  
  
/** 
 * @author JITHINRAJ.P
 * @author email : jithinrajktd@gmail.com
 */  
  
@Path("/webservice")  
public class WebController {  
   
     @GET  
     @Path("/echo/{message}")  
     @Produces("text/plain")  
     public String showMsg(@PathParam("message") String message){  
         return message;      
     }  
       
     
     @GET 
     @Path("/insert/{name}/{by}/{likes}/{year}/{description}")  
     @Produces("text/plain")  
     public String insert(@PathParam("name") String name  , @PathParam("description") String description , @PathParam("likes") Long likes , @PathParam("year") String year , @PathParam("by") String by){
      MongoDBSingleton dbSingleton = MongoDBSingleton.getInstance();
      DB db = dbSingleton.getTestdb();
      DBCollection coll = db.getCollection("Books"); 
      BasicDBObject doc = new BasicDBObject("title", name).
        append("description", description).
        append("likes", likes).
        append("year", year).
        append("by", by);
      coll.insert(doc);
      return db.isAuthenticated() + " ; " + db.getName();

     }  
     
     @GET 
     @Path("/getRecords")  
     @Produces(MediaType.APPLICATION_JSON)  
     public List getRecords(){
      MongoDBSingleton dbSingleton = MongoDBSingleton.getInstance();
      DB db = dbSingleton.getTestdb();
      DBCollection coll = db.getCollection("Books"); 
      DBCursor cursor = coll.find().sort(new BasicDBObject("by", 1));
      List list = new ArrayList();
      while (cursor.hasNext()) { 
             DBObject o = cursor.next();
             Books bools = new Books();
             bools.setTitle((String) o.get("title"));
             bools.setDescription((String) o.get("description"));
             bools.setYear((String) o.get("year"));
             bools.setBy((String) o.get("by"));
             bools.setLikes((Long) o.get("likes"));
             list.add(bools);
          }
      return list;
     } 
     
     @GET 
     @Path("/getRecord/{title}")  
     @Produces(MediaType.APPLICATION_JSON)  
     public List getRecordFromName(@PathParam("title") String message){
      MongoDBSingleton dbSingleton = MongoDBSingleton.getInstance();
      DB db = dbSingleton.getTestdb();
      DBCollection coll = db.getCollection("TestDude"); 
      DBCursor cursor = coll.find(new BasicDBObject("title", message));
      List list = new ArrayList();
      while (cursor.hasNext()) { 
             DBObject o = cursor.next();
             Books bools = new Books();
             bools.setTitle((String) o.get("title"));
             bools.setDescription((String) o.get("description"));
             bools.setYear((String) o.get("year")); 
             bools.setBy((String) o.get("by"));
             list.add(bools);
          }
      return list;
     } 
}  

Results   

Test your Application


You can test your web application by using the echo method added in the Webcontroller class. 

eg : http://your-website.com/api/webservice/echo/message




Insert Book

For insert, load url : http://your-server.com/insert/book name/author/likes/year/description



Get all Books

For retrieve the all book data, load url http://your-server.com/api/webservice/getRecords/


Response :






{
  "Books": [
    {
      "by": "Chetan Bhagat",
      "description": "Fourth book by the bestselling author Chetan Bhagat. 2 States is a story about Krish and Ananya.",
      "likes": "200000",
      "title": "2 States: The Story of My Marriage",
      "year": "2009"
    },
    {
      "by": "E L James",
      "description": "Just when it seems that their strength together will eclipse any obstacle, misfortune, malice, and fate conspire to make Ana’s deepest fears turn to reality. This book is intended for mature audiences. From the Trade Paperback edition.",
      "likes": "2000000",
      "title": "Fifty Shades Freed: Book Three of the Fifty Shades Trilogy",
      "year": "2012"
    },
    {
      "by": "F. Scott Fitzgerald",
      "description": "This edition is fully annotated with a fine Introduction incorporating new interpretation and detailing Fitzgerald's struggle to write the novel, its critical reception and its significance for future generations.",
      "likes": "2000000",
      "title": "The Great Gatsby",
      "year": "1998"
    },
    {
      "by": "Herman Melville",
      "description": "A literary classic that wasn't recognized for its merits until decades after its publication, Herman Melville's Moby-Dick tells the tale of a whaling ship and its crew, who are carried progressively further out to sea by the fiery Captain",
      "likes": "100000",
      "title": "Moby Dick",
      "year": "1892"
    },
    {
      "by": "Paulo Coelho",
      "description": "Every few decades a book is published that changes the lives of its readers forever.",
      "likes": "5000000",
      "title": "The Alchemist LP: A Fable About Following Your Dream",
      "year": "2005"
    }
  ]
}



Get a Book by title

For retrieve the all book data, load url http://your-server.com/api/webservice/getRecords/

Eg : - http://your-website.com/api/webservice/getRecord/Moby Dick
Response :




{
  "Books": {
    "by": "Herman Melville",
    "description": "A literary classic that wasn't recognized for its merits until decades after its publication, Herman Melville's Moby-Dick tells the tale of a whaling ship and its crew, who are carried progressively further out to sea by the fiery Captain",
    "likes": "0",
    "title": "Moby Dick",
    "year": "1892"
  }
}


10 comments:

  1. How to import this project in Eclipse?

    ReplyDelete
  2. Hi, I have read your blog and I got a useful information from this blog. Thanks for sharing, keep posting.

    MongoDB Training in Chennai

    ReplyDelete
  3. the exported built war file host to the tomcat server is not working, with the resource is not found message. Please, say about that too

    ReplyDelete
  4. Hi, i get this error "StandardWrapperValve[jersey-serlvet]: Servlet.service() for servlet jersey-serlvet threw exception
    java.lang.NullPointerException
    at raspberry.rest.demo.WebController.getRecords(WebController.java:59)" for some reason it wont connect to mongodb, any ideas? thanks

    ReplyDelete
  5. Add below lines in context if you are getting error while deploying.

    com.sun.jersey.config.property.packages
    raspberry.rest.demo

    ReplyDelete
  6. Hey I think you meant "raw string as post body" and not "post string as raw body" here:

    https://stackoverflow.com/a/35789293

    Best check yourself.

    ReplyDelete