Environment
- Apache Tomcat 7 (dockerized version)
- MongoDB 2.6.7 (dockerized version)
- JDK 7
- Jersey Server 1.9
- Spring 4.1.6
- Clients: Java, Bash, Python, Javascript
Introduction and Project Description
- A JAX-RS web application implemented in Jersey
- Build Automation is handled using Maven
- Deployment Environment is Apache Tomcat 7 (dockerized version)
- Consumer can POST or GET a book entity.
- Data is persisted in MongoDB (dockerized version)
- The Spring Data Framework (1.7.0) is used to wrap the MongoDB Java Driver (2.11.0)
- The Spring Framework (4.1.6 BOM) is used for component management
- Consumers are provided in Java, Python and Javascript (jQuery 2.x)
The application component model:
Fig 1: Component Model |
The consumer can POST or GET a book entity to the application.
A JSON representation of the book entity looks like this: {"author":"Patrick OBrian","id":123,"title":"The Wine Dark Sea"}
The project source code is available at Github (reference below).
GET
The JAX-RS compliant-interface looks like:
@Path("/endpoint") public class RestEndpoint { public static LogManager logger = new LogManager(RestEndpoint.class); @GET @Path("/get") @Produces(MediaType.APPLICATION_JSON) public Object get1(@QueryParam("id") Long id) { return getController().get(id); } @GET @Path("{id}") @Produces(MediaType.APPLICATION_JSON) public Object get2(@PathParam("id") Long id) { return get1(id); } // define POST methods ... }
Using the first GET method, a consumer can query the system like this:
$ curl http://host:8080/blogger/demo/endpoint/123 {"author":"Patrick OBrian","id":123,"title":"The Wine Dark Sea"}
and use the second method like this:
$ curl http://host:8080/blogger/demo/endpoint/get?id=123 {"author":"Patrick OBrian","id":123,"title":"The Wine Dark Sea"}
Using the requests module in Python, the GET methods look like this:
import requests def g1(): r = requests.get('http://host:8080/blogger/demo/endpoint/123') test(r.status_code) def g2(): payload = { 'id': '123' } headers = {'content-type': 'application/json'} r = requests.get('http://host:8080/blogger/demo/endpoint/get', params=payload) test(r.status_code) def test(status_code): print 'status_code:', status_code assert (200 == status_code or 201 == status_code) g1() g2()
Using jQuery, the GET looks like this:
<html> <head> <script src="js/jquery-2.1.3.js"></script> <script> var BASE = "http://host:8080/blogger/demo/endpoint/"; $(document).ready(function() { $("#btnSubmitGET").click(function() { get($("#txtGET").val()); }); }); /* get data by id */ function get(id) { var url = BASE + id; $.getJSON(url, function(data) { /* create a list from the results */ var items = []; $.each(data, function(key, val) { items.push("<li id='" + key + "'>" + val + "</li>"); }); $("<ul/>", { "class" : "my-new-list", html : items.join("") }).appendTo("body"); }); } </script> </head> <body> <input type="text" name="id" value="9956" id="txtGET" class="id" /> <input id="btnSubmitGET" type="submit" value="GET" /> </body> </html>
and the result like this:
Fig 2: Results |
POST
I've defined three POST methods that look like this:
@POST @Path("/post") @Consumes(MediaType.APPLICATION_JSON) public Response post1(Book book) { logger.info("Invoked Post Method 1:\n\t%s", BookAdapter.toString(book)); return getController().post(book); } @POST @Path("/form") @Consumes(MediaType.APPLICATION_FORM_URLENCODED) public Response post2(@FormParam("id") long id, @FormParam("author") String author, @FormParam("title") String title) { logger.info("Invoked Post Method 2:\n\tid = %s, author = %s, title = %s", id, author, title); return post1(BookAdapter.transform(id, title, author)); } @POST @Path("/{param}") public Response post3(@PathParam("param") String msg) { logger.info("Invoked Post Method 3:\n\t%s", msg); try { Book book = GsonUtils.toObject(msg, Book.class); if (null != book) return post1(book); } catch (JsonSyntaxException e) { logger.error(e, "Invalid JSON (%s)", msg); } return ResponseAdapter.postFail("book", msg); }
In the first case, I can GET and POST a Book entity from a Java consumer, like this:
package com.trimc.blogger.jaxrs; import static org.junit.Assert.assertEquals; import javax.ws.rs.core.MediaType; import org.swtk.common.framework.LogManager; import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.ClientResponse; import com.sun.jersey.api.client.WebResource; import com.trimc.blogger.jaxrs.dto.Book; import com.trimc.blogger.jaxrs.dto.BookAdapter; public class WebResourceTester { public static LogManager logger = new LogManager(WebResourceTester.class); public static void main(String... args) throws Throwable { Client client = Client.create(); Book book = BookAdapter.transform(12345l, "Nutmeg of Consolation", "Patrick O'Brian"); WebResource webResourcePost = client.resource("http://host:8080/blogger/demo/endpoint/post"); ClientResponse responsePost = webResourcePost.type(MediaType.APPLICATION_JSON).post(ClientResponse.class, book); logger.info("%s", responsePost.getEntity(String.class)); WebResource webResourceGet = client.resource("http://host:8080/blogger/demo/endpoint/" + book.getId()); ClientResponse responseGet = webResourceGet.type(MediaType.APPLICATION_JSON).get(ClientResponse.class); Book _book = responseGet.getEntity(Book.class); assertEquals(book.hashCode(), _book.hashCode()); } }
In the form POST method, I can use standard HTML:
<html> <head> <body> <h3>Demonstrate HTML Form POST</h3> <form action="http://192.168.1.7:8080/blogger/demo/endpoint/form" method="post"> <p> ID : <input type="text" name="id" value="123" /> </p> <p> Author : <input type="text" name="author" value="Patrick OBrian" /> </p> <p> Title : <input type="text" name="title" value="The Wine Dark Sea" /> </p> <input type="submit" value="POST" /> </form> </body> </html>
Fig 3: Form POST |
and the result demonstrated via RoboMongo:
Fig 4: JSON Results |
The third method in jQuery looks like this:
<html> <head> <script src="js/jquery-2.1.3.js"></script> <script> var BASE = "http://host:8080/blogger/demo/endpoint/"; $(document).ready(function() { initTextarea(); $("#btnSubmitPOST").click(function() { post($("#txtPOST").val()); }); }); /* initialize the textarea with a payload */ function initTextarea() { var payload = { "author" : "Patrick O'Brian", "id" : 1234, "title" : "The Wine Dark Sea" }; $("#txtPOST").val(JSON.stringify(payload)); } /* post json data */ function post(id) { try { var url = BASE + id; $.post(url, function(data, status) { alert("Data: " + data + "\nStatus: " + status); }); } catch (e) { alert(e); } } </script> </head> <body> <h3>Demonstrate JSON POST</h3> <textarea name="id" id="txtPOST" class="id" rows="4" cols="50"></textarea> <input id="btnSubmitPOST" type="submit" value="POST" /> </body> </html>
The submission is just JSON in a textarea sent directly to the client:
Fig 5: JSON Post Form |
and a demonstration via Robomongo that the data was indeed persisted:
Fig 6: JSON Results |
The last two approaches are also shown below in Python:
import requests # STATUS CODES: # <http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html> # 200 = OK # 201 = Created def post2(): payload = { 'author' : 'p5-author', 'id' : '9995', 'title' : 'p5-title' } headers = {u'content-type': u'application/x-www-form-urlencoded'} r = requests.post("http://host:8080/blogger/demo/endpoint/form", params=payload, headers=headers) test(r.status_code) return r.text def post3(): r = requests.post( 'http://host:8080/blogger/demo/endpoint/{"author":"this is my content","title":"my title","id":9956}' ) test(r.status_code) return r.text def test(status_code): print 'status_code:', status_code assert (200 == status_code or 201 == status_code) p5(); p6()
References
- [GitHub] Source Code for this article [or, Google Drive for a zip file]
- Resources:
- GitHub] Apache Tomcat 7 (configured for this blog post)
- [Docker Register] MongoDB Dockerfile
- HOWTO Articles:
- [Blog] Setting up Apache Tomcat and Docker
- [Blog] Working with MongoDB (Installation and Usage)
- [Blog] Using Maven for Build Automation