Creating RESTful Webservice and Client API in JAX-RS 2.0

SHARE & COMMENT :

In my previous post I wrote about using JAXB to marshall and unmarshal XML data and in that I used the example of simple Book management system. In this post I am expanding on that to create a RESTful Webservice using the refrence implementation of JAX-RS i.e Jersey and also using the new Client API introduced in JAX-RS 2.0 which comes with JavaEE 7. The RESTful Webservice to be developed will support the following:

  1. To add a details of new book.
  2. To get the details of a book given its ISBN.
  3. To get the details of all the books present in the database.

The database in my example is not the usual database but just a Java Collection object which contains list of Book objects.

If you are not familiar with REST and its concepts I would suggest you to search on the net for some basic information before proceeding further.

Now lets look at creating RESTful Web Service using JAX-RS reference implementation.

Creating a RESTful Web Service

  1. Annotate the class representing some service with @javax.ws.rs.Path annotation and also pass the URL at which this service can be invoked. This service class should have a default public constructor and the class should not be final or abstract.
  2. To support different HTTP methods define different methods within the service class and for each method annotation with @javax.ws.rs.GET or @javax.ws.rs.POST or @javax.ws.rs.PUT or @javax.ws.rs.DELETE depending on which HTTP method you want to be handled by the methods.
  3. One can annotate at the class level or at the method level the format of data accepted by the RESTful service and the format of data generated by the RESTful Service by using the @javax.ws.rs.Produces and @javax.ws.rs.Consumes annotations.

Lets build a RESTful webservice which will support the following operations:

  1. To list all the books present in the database.
  2. To list the details of a particular book.
  3. To add details for new book.

Building the RESTful Webservice

Let us identify the Path which can be used to perform the above stated operations:

  1. To list all the books present in the database – The URL for this would be a GET request to /book/
  2. To list the details of a particular book – The URL for this would be a GET request to /book/{isbn}
  3. To add details for new book – The URL for this would be a POST request to /book/

All of the above services accept XML data and generate XML data as response. The implementation for the RESTful service which supports all of these operations is given below:

import db.BookDb;
import java.net.URISyntaxException;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import model.Book;
import model.Books;

/**
 * RESTful Service for operations on Book like adding new book,
 * viewing the data for a book given its ISBN, listing all the books.
 */
@Path("/book")
@Produces(MediaType.APPLICATION_XML)
@Consumes(MediaType.APPLICATION_XML)
public class BookRestService {

  @Context
  UriInfo uriInfo;

  /**
   * Service method to return all the books present in the database in the form
   * of XML. The conversion from Java object to XML is handled by JAXB.
   */
  @GET
  public Books getAllBooks(){
    Books books = BookDb.bookDb.getAllBooks();
    return books;
  }

  /**
   * Service method to return the details of the book represented by the ISBN
   * number. The conversion from Book java object to XML is handled by JAXB.
   */
  @GET
  @Path("{isbn}")
  public Book getBook(@PathParam("isbn") String isbn){
    Book book = BookDb.bookDb.getBookByIsbn(isbn);
    if ( book == null ){
      throw new NotFoundException("No book found with the matching ISBN: "+ isbn);
    }
    return book;
  }

  /**
   * Service method to add the details of the new book. The data for the details
   * of the book is sent in the form of XML which is converted to Book object
   * by the JAXB. And return the the details page displaying the details
   * of the new Book added.
   */
  @POST
  @Consumes(MediaType.APPLICATION_XML)
  public Response createBook(Book book) throws URISyntaxException{
    if ( book == null){
      throw new BadRequestException();
    }

    BookDb.bookDb.addToBookDb(book);
    return Response.created(uriInfo.getAbsolutePathBuilder().path(book.isbn).build()).build();
  }
}

In the previous post I had shown how to create XML data given Book object or Books object and also how to create Book object or Books object given the XML data representing it using JAXB. This complete RESTful Webservice implementation shown above is based on top of this JAXB implementation. The RESTful API i.e JAX-RS does the conversion from Java object to XML and from XML to Java Object using the JAXB implementation there by making it easier for development of the RESTful Webservice.

Using JAX-RS Client API to access the RESTful Webservice

In JavaEE 7 a new Client API has been added to the JAX-RS API. I will make use of that API to acces the RESTful Webservice developed above. These are the basic tasks to be performed to use the client API to access the RESTful Webservice:

  1. Obtain the instance of javax.ws.rs.client.Client class which is the basic and entry point to invoking RESTful Webservices.
  2. To invoke a RESTful Webserivce at some location or URI create an instance of javax.ws.rs.client.WebTarget using the instance of Client class.
  3. Once you have the target you will have to populate the target with the required data like query params, MIME Type, any post data and then create a request of appropriate HTTP method type which would be an instance of javax.ws.rs.client.Invocation.
  4. Use the instance of javax.ws.rs.client.Invocation to obtain the response from the desired RESTful Webservice.

Lets apply the above steps to invoke the RESTful Webservice at “http:///rs/book”. In my case the Book RESTful Webserivce is available at: http://localhost:8080/RestfulDemo/rs/book.

Invoking the getAllBooks() RESTful Webservice

Lets look at the code which invokes the getAllBooks() RESTful Webservice:

import java.util.List;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import model.Book;
import model.Books;
import model.Review;
import rest.BookRestService;

/**
 * Testing the Client API by invoking the Book RESTful Webservice.
 */
public class BookRestClient {

  public static void main(String[] args) {

    invokeAllBooksService();
  }

  private static void invokeAllBooksService() {
    System.out.println("****Invoking the All Books Service****");
    //Obtaining the instance of Client which will be entry point to invoking REST Services.
    Client client = ClientBuilder.newClient();

    //Targeting the RESTful Webserivce we want to invoke by capturing it in WebTarget instance.
    WebTarget allBooksTarget = client.target("http://localhost:8080/RestfulDemo/rs/book");

    //Building the request i.e a GET request to the RESTful Webservice defined
    //by the URI in the WebTarget instance.
    Invocation allBooksInvocation = allBooksTarget.request().buildGet();

    //Invoking the request to the RESTful API and capturing the Response.
    Response response = allBooksInvocation.invoke();

    //As we know that this RESTful Webserivce returns the XML data which can be unmarshalled
    //into the instance of Books by using JAXB.
    Books books = response.readEntity(Books.class);

    for (Book book : books.myBooks) {
      printBook(book);
    }
  }

  private static String joinList(List list) {
    StringBuilder builder = new StringBuilder();
    for (String str : list) {
      builder.append(str).append(",");
    }
    return builder.toString().substring(0, builder.length() - 1);
  }

  private static void printBook(Book book) {
    System.out.println("Details for: " + book.title);
    System.out.println("Author: " + joinList(book.authors));
    System.out.println("ISBN: " + book.isbn);
    System.out.println("Publisher: " + book.publisher);
    System.out.println("Cost: " + book.price);
    System.out.println("Publication year: " + book.year);
    System.out.println("Reviews: ");
    for (Review review : book.reviews) {
      System.out.println(review.content + " by " + review.author + " posted on " + review.getPostedOn());
    }
  }
}

Invoking the getBook() RESTful Webservice

In this we will invoke the Book RESTful Webservice by passing in an ISBN value which will be of the form “/book/9781259002465″.


private static void invokeGetBookService() {
  System.out.println("****Invoking the Get Book Service****");
  String isbn = "9781259002465";
  Client client = ClientBuilder.newClient();
  WebTarget target = client.target("http://localhost:8080/RestfulDemo/rs/book/"+isbn);
  Response response = target.request().buildGet().invoke();
  Book book = response.readEntity(Book.class);
  printBook(book);
}

private static void printBook(Book book) {
  System.out.println("Details for: " + book.title);
  System.out.println("Author: " + joinList(book.authors));
  System.out.println("ISBN: " + book.isbn);
  System.out.println("Publisher: " + book.publisher);
  System.out.println("Cost: " + book.price);
  System.out.println("Publication year: " + book.year);
  System.out.println("Reviews: ");
  for (Review review : book.reviews) {
    System.out.println(review.content + " by " + review.author + " posted on " + review.getPostedOn());
  }
}

Invoking the createBook() RESTful Webservice

This RESTful Webservice is used to add the details of new book. And once added it gives the URL to the user to view details of the new book.

private static void invokeCreateBookService() {
  System.out.println("****Invoking the Create Book Service****");

  Calendar calendar = Calendar.getInstance();
  Date today = calendar.getTime();
  calendar.add(Calendar.DATE, -4);
  Date olderDay1  =  calendar.getTime();

  Book book = new Book();
  book.authors = Arrays.asList("Gayle Laakmann McDowell");
  book.binding = Binding.PAPERBACK;
  book.isbn = "9788126538058";
  book.numberOfPages = 280;
  book.price = 260.0;
  book.publisher = "Wiley/Goels Computer Hut";
  book.title = "The Google Resume: How to Prepare for a Career and land a Job at Apple, Microsoft, Google, or Any Top Tech Company";
  book.year = 2012;
  book.reviews = (Arrays.asList(new Review("Very Precise and handy", "Shameer", today, Rating.FOUR),
          new Review("Best guide for cover letters, resumes etc", "Harshith", olderDay1, Rating.FIVE)));

  Client client = ClientBuilder.newClient();
  WebTarget target = client.target("http://localhost:8080/RestfulDemo/rs/book");
  Response response = target.request().buildPost(Entity.entity(book, MediaType.APPLICATION_XML)).invoke();
  System.out.println(response.getLocation().getPath());
}

The complete code for invoking the Book RESTful Webservice using the new Client API in JAX-RS 2.0 is give below:


import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import model.Binding;
import model.Book;
import model.Books;
import model.Rating;
import model.Review;

/**
 * Testing the Client API by invoking the Book RESTful Webservice.
 */
public class BookRestClient {

  public static void main(String[] args) {

    invokeAllBooksService();
    invokeGetBookService("9781259002465");
    invokeCreateBookService();
    //Trying to read the book details created by the above method.
    invokeGetBookService("9788126538058");
  }

  private static void invokeAllBooksService() {
    System.out.println("****Invoking the All Books Service****");
    //Obtaining the instance of Client which will be entry point to invoking REST Services.
    Client client = ClientBuilder.newClient();

    //Targeting the RESTful Webserivce we want to invoke by capturing it in WebTarget instance.
    WebTarget allBooksTarget = client.target("http://localhost:8080/RestfulDemo/rs/book");

    //Building the request i.e a GET request to the RESTful Webservice defined
    //by the URI in the WebTarget instance.
    Invocation allBooksInvocation = allBooksTarget.request().buildGet();

    //Invoking the request to the RESTful API and capturing the Response.
    Response response = allBooksInvocation.invoke();

    //As we know that this RESTful Webserivce returns the XML data which can be unmarshalled
    //into the instance of Books by using JAXB.
    Books books = response.readEntity(Books.class);

    for (Book book : books.myBooks) {
      printBook(book);
    }
  }

  private static void invokeGetBookService(String isbn) {
    System.out.println("****Invoking the Get Book Service****");
    Client client = ClientBuilder.newClient();
    WebTarget target = client.target("http://localhost:8080/RestfulDemo/rs/book/" + isbn);
    Response response = target.request().buildGet().invoke();
    Book book = response.readEntity(Book.class);
    printBook(book);
  }

  private static void invokeCreateBookService() {
    System.out.println("****Invoking the Create Book Service****");

    Calendar calendar = Calendar.getInstance();
    Date today = calendar.getTime();
    calendar.add(Calendar.DATE, -4);
    Date olderDay1  =  calendar.getTime();

    Book book = new Book();
    book.authors = Arrays.asList("Gayle Laakmann McDowell");
    book.binding = Binding.PAPERBACK;
    book.isbn = "9788126538058";
    book.numberOfPages = 280;
    book.price = 260.0;
    book.publisher = "Wiley/Goels Computer Hut";
    book.title = "The Google Resume: How to Prepare for a Career and land a Job at Apple, Microsoft, Google, or Any Top Tech Company";
    book.year = 2012;
    book.reviews = (Arrays.asList(new Review("Very Precise and handy", "Shameer", today, Rating.FOUR),
            new Review("Best guide for cover letters, resumes etc", "Harshith", olderDay1, Rating.FIVE)));

    Client client = ClientBuilder.newClient();
    WebTarget target = client.target("http://localhost:8080/RestfulDemo/rs/book");
    Response response = target.request().buildPost(Entity.entity(book, MediaType.APPLICATION_XML)).invoke();
    System.out.println(response.getLocation().getPath());
  }

  private static String joinList(List list) {
    StringBuilder builder = new StringBuilder();
    for (String str : list) {
      builder.append(str).append(",");
    }
    return builder.toString().substring(0, builder.length() - 1);
  }

  private static void printBook(Book book) {
    System.out.println("Details for: " + book.title);
    System.out.println("Author: " + joinList(book.authors));
    System.out.println("ISBN: " + book.isbn);
    System.out.println("Publisher: " + book.publisher);
    System.out.println("Cost: " + book.price);
    System.out.println("Publication year: " + book.year);
    System.out.println("Reviews: ");
    for (Review review : book.reviews) {
      System.out.println(review.content + " by " + review.author + " posted on " + review.getPostedOn());
    }
  }
}

I am not printing the output here because the output contains the complete XML structure which will be huge. If you want to access this complete sample you can fork the Github repository at: https://github.com/javabeat/javaee7-restdemo and load the project in Netbeans 7.3+ with JavaEE 7 support.

Do let me know if you are unable to get the code working or understand something from the code.

Comments

comments

About Mohamed Sanaulla

In his day job he works on developing enterprise applications using ADF. He is also the moderator of JavaRanch forums and an avid blogger.

Speak Your Mind

*

Close
Please support the site
By clicking any of these buttons you help our site to get better