Chapter 46. JAX-RS 2.0 Client API

Abstract

JAX-RS 2.0 defines a full-featured client API which can be used for making REST invocations or any HTTP client invocations. This includes a fluent API (to simplify building up requests), a framework for parsing messages (based on a type of plug-in known as an entity provider), and support for asynchronous invocations on the client side.

46.1. Introduction to the JAX-RS 2.0 Client API

Overview

JAX-RS 2.0 defines a fluent API for JAX-RS clients, which enables you to build up a HTTP request step-by-step and then invoke the request using the appropriate HTTP verb (GET, POST, PUT, or DELETE).
Note
It is also possible to define a JAX-RS client in Blueprint XML or Spring XML (using the jaxrs:client element). For details of this approach, see Section 16.2, “Configuring JAX-RS Client Endpoints”.

Dependencies

To use the JAX-RS 2.0 client API in your application, you must add the following Maven dependency to your project's pom.xml file:
<dependency>
  <groupId>org.apache.cxf</groupId>
  <artifactId>cxf-rt-rs-client</artifactId>
  <version>3.1.5.redhat-630187</version>
</dependency>
If you plan to use the asynchronous invocation feature (see Section 46.6, “Asynchronous Processing on the Client”), you also need the following Maven dependency:
<dependency>
  <groupId>org.apache.cxf</groupId>
  <artifactId>cxf-rt-transports-http-hc</artifactId>
  <version>3.1.5.redhat-630187</version>
</dependency>

Client API package

The JAX-RS 2.0 client interfaces and classes are located in the following Java package:
javax.ws.rs.client
When developing JAX-RS 2.0 Java clients, you also typically need to access classes from the core package:
javax.ws.rs.core

Example of a simple client request

The following code fragment shows a simple example, where the JAX-RS 2.0 client API is used to make an invocation on the http://example.org/bookstore JAX-RS service, invoking with the GET HTTP method:
// Java
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Client;
import javax.ws.rs.core.Response;
...
Client client = ClientBuilder.newClient();
Response res = client.target("http://example.org/bookstore/books/123")
    .request("application/xml").get();

Fluent API

The JAX-RS 2.0 client API is designed as a fluent API (sometimes called a Domain Specific Language). In the fluent API, a chain of Java methods is invoked in a single statement, in such a way that the Java methods look like the commands from a simple language. In JAX-RS 2.0, the fluent API is used to build and invoke a REST request.

Steps to make a REST invocation

Using the JAX-RS 2.0 client API, a client invocation is built and invoked in a series of steps, as follows:
  1. Bootstrap the client.
  2. Configure the target.
  3. Build and make the invocation.
  4. Parse the response.

Bootstrap the client

The first step is to bootstrap the client, by creating a javax.ws.rs.client.Client object. This Client instance is a relatively heavyweight object, which represents the stack of technologies required to support a JAX-RS client (possibly including, interceptors and additional CXF features). Ideally, you should re-use client objects when you can, instead of creating new ones.
To create a new Client object, invoke a static method on the ClientBuilder class, as follows:
// Java
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Client;
...
Client client = ClientBuilder.newClient();
...

Configure the target

By configuring the target, you effectively define the URI that will be used for the REST invocation. The following example shows how you can define a base URI, base, and then add additional path segments to the base URI, using the path(String) method:
// Java
import javax.ws.rs.client.WebTarget;
...
WebTarget base = client.target("http://example.org/bookstore/");
WebTarget books = base.path("books").path("{id}");
...

Build and make the invocation

This is really two steps rolled up into one: firstly, you build up the HTTP request (including headers, accepted media types, and so on); and secondly, you invoke the relevant HTTP method (optionally providing a request message body, if one is required).
For example, to create and invoke a request that accepts the application/xml media type:
// Java
import javax.ws.rs.core.Response;
...
Response resp = books.resolveTemplate("id", "123").request("application/xml").get();

Parse the response

Finally, you need to parse the respose, resp, obtained in the previous step. Usually, the response is returned in the form of a javax.ws.rs.core.Response object, which encapsulates HTTP headers, along with other HTTP metadata, and the HTTP message body (if any).
If you want to access the returned HTTP message in String format, you can easily do so by invoking the readEntity method with a String.class argument, as follows:
// Java
...
String msg = resp.readEntity(String.class);
You can always access the message body of a response as a String, by specifying String.class as the argument to readEntity. For more general transformations or conversions of the message body, you can provide an entity provider to perform the conversion. For more details, see Section 46.4, “Parsing Requests and Responses”.