The JAX-RS Client API

JAX-RS, Restlet, and the JAX-WS @WebServiceProvider frameworks for RESTful services include client-side APIs. These APIs are meant to simplify the task of writing RESTful clients in general, not just clients against a RESTful service implemented in a particular framework. To underscore the point, this section takes a look at the JAX-RS client-side API (see Example 3-18); the client, however, goes against the servlet-based predictions2 RESTful service from Chapter 2.

Example 3-18. A sample client using the JAX-RS client-side API

package jerseyClient;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import javax.ws.rs.core.MediaType;
import com.sun.jersey.api.representation.Form;

public class JerseyClient {
    private static final String baseUrl = "http://localhost:8080/predictions2";

    public static void main(String[ ] args) {
        new JerseyClient().demo();
    }
    private void demo() {
        Client client = Client.create();
        client.setFollowRedirects(true); // in case the service redirects
        WebResource resource = client.resource(baseUrl);
        getAllDemo(resource);
        postDemo(resource); // same resource but different verb
        String url = baseUrl + "?id=32";
        resource = client.resource(url);
        getOneDemo(resource);
        deleteDemo(resource); // delete id = 32
    }
    private void getAllDemo(WebResource resource) {
        // GET all XML
        String response =
            resource.accept(MediaType.APPLICATION_XML_TYPE).get(String.class);
        report("GET all in XML:\n", response);
        // GET all JSON
        response =
            resource.accept(MediaType.APPLICATION_JSON_TYPE).get(String.class);
        report("GET all in JSON:\n", response);
    }
    private void getOneDemo(WebResource resource) {
        String response =
            resource.accept(MediaType.APPLICATION_XML_TYPE).get(String.class);
        report("GET one in XML:\n", response);
        response =
            resource.accept(MediaType.APPLICATION_JSON_TYPE).get(String.class);
        report("GET one in JSON:\n", response);
    }
    private void postDemo(WebResource resource) {
        Form form = new Form(); // HTTP body, a simple hash
        form.add("who", "William Butler Yeats");
        form.add("what", "I know that I shall meet my fate");

        String response =
            resource.type(MediaType.APPLICATION_FORM_URLENCODED_TYPE)
            .accept(MediaType.TEXT_PLAIN_TYPE)
            .post(String.class, form);
        report("POST:\n", response);
    }
    private void deleteDemo(WebResource resource) {
        String response =
            resource.accept(MediaType.TEXT_PLAIN_TYPE).delete(String.class);
        report("DELETE:\n", response);
    }
    private void report(String msg, String response) {
        System.out.println("\n" + msg + response);
    }
}

The JerseyClient (see Example 3-18) against the servlet-based predictions2 RESTful service supports all of the CRUD operations. (An executable JAR with the client is included in the ZIP with the sample code.) This client underscores that the JAX-RS client API is not restricted to JAX-RS services. In any case, the JerseyClient uses some nice features of the JAX-RS client-side API. For example, the predictions2 service uses the same URI in a GET request that returns XML as in one that returns JSON. What differentiates the two requests is that the one for JSON has the key/value pair:

accept: application/json

or the equivalent in the HTTP headers of a GET request. In the getAllDemo method of the JerseyClient, the two forms of the GET request are expressed at a high level:

resource.accept(MediaType.APPLICATION_XML_TYPE).get(String.class);  // XML
resource.accept(MediaType.APPLICATION_JSON_TYPE).get(String.class); // JSON

There is no need for the programmer to inject, using a low-level API, inject this key/value pair into the HTTP headers using a low-level API:

accept: application/json

By the way, the get(String.class) at the end of each statement signals that the response to the GET request should be text, a Java String. The API accepts JAX-B types as well so that, for example, a GET request could indicate that it expects a Prediction object rather than a String one.

The setup for making CRUD calls is uncomplicated. A Client instance is created, which can be used to create arbitrarily many WebResource instances, each of which wraps a URL. Here, for review, is a slice of the JerseyClient:

Client client = Client.create();
client.setFollowRedirects(true); // in case the service redirects
WebResource resource = client.resource(baseUrl); // service URL

In version 2, the JAX-RS client API introduces some advanced features such as filters and asynchronous requests. These features will be examined in the next chapter but in the context of SOAP-based web services. Restlet has a client API comparable to the one in JAX-RS. The JAX-WS client API for calls against the @WebServiceProvider is at a lower level than both JAX-RS and Restlet. This is appropriate in that the @WebServiceProvider service-side API is deliberately low-level. All of these client-side APIs add a RESTful layer to the familiar Java classes such as URLConnection.