Chapter 37. Client Framework

The RESTEasy Client Framework is the alternative to the JAX-RS server-side specification. Instead of using JAX-RS annotations to map an incoming request to your RESTful Web Service method, the client framework creates a HTTP request to invoke on a remote RESTful Web Service, which can be any web resource that accepts HTTP requests.
RESTEasy has a client proxy framework that lets you invoke upon a remote HTTP resource by using JAX-RS annotations. You can write a Java interface and use JAX-RS annotations on methods and the interface. For example:
public interface SimpleClient
{
   @GET
   @Path("basic")
   @Produces("text/plain")
   String getBasic();

   @PUT
   @Path("basic")
   @Consumes("text/plain")
   void putBasic(String body);

   @GET
   @Path("queryParam")
   @Produces("text/plain")
   String getQueryParam(@QueryParam("param")String param);

   @GET
   @Path("matrixParam")
   @Produces("text/plain")
   String getMatrixParam(@MatrixParam("param")String param);

   @GET
   @Path("uriParam/{param}")
   @Produces("text/plain")
   int getUriParam(@PathParam("param")int param);
}
The RESTEasy API is simple, and based on Apache HttpClient. You generate a proxy, and invoke methods on the proxy. The invoked method is then translated to a HTTP request (based on the method's annotations) and posted to the server. To set it up:
            import org.resteasy.plugins.client.httpclient.ProxyFactory;
            ...
            // this initialization only needs to be done once per VM
            RegisterBuiltin.register(ResteasyProviderFactory.getInstance());


            SimpleClient client = ProxyFactory.create(SimpleClient.class, "http://localhost:8081");
            client.putBasic("hello world");
See the ProxyFactory Java Documentation for more options. For instance, you may want to fine tune the HttpClient configuration.
@CookieParam creates a cookie header to send to the server. If you allocate your own javax.ws.rs.core.Cookie object and pass it as a parameter to a client proxy method, you do not require @CookieParam — the client framework understands that you are passing a cookie to the server, so no extra metadata is required.
The client framework can use the same providers available on the server. You must manually register them through the ResteasyProviderFactory singleton using the addMessageBodyReader() and addMessageBodyWriter() methods.
        ResteasyProviderFactory.getInstance().addMessageBodyReader(MyReader.class);

37.1. Abstract Responses

When you need to access the response code or the response headers of a client request, the Client-Proxy framework provides two options:
You can return a javax.ws.rs.core.Response.Status enumeration from your method calls, like so:
@Path("/")
public interface MyProxy {
   @POST
   Response.Status updateSite(MyPojo pojo);
}
After invoking on the server, the client proxy internally converts the HTTP response code into a Response.Status enumeration.
You can retrieve all data associated with a request with the org.resteasy.spi.ClientResponse interface:
/**
 * Response extension for the RESTEasy client framework. Use this, or Response
 * in your client proxy interface method return type declarations if you want
 * access to the response entity as well as status and header information.
 *
 * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
 * @version $Revision: 1 $
 */
public abstract class ClientResponse<T> extends Response
{
   /**
    * This method returns the same exact map as Response.getMetadata() except as a map of strings 
    * rather than objects.
    *
    * @return
    */
   public abstract MultivaluedMap<String, String> getHeaders();

   public abstract Response.Status getResponseStatus();

   /**
    * Unmarshal the target entity from the response OutputStream.  You must have type information
    * set via <T> otherwise, this will not work.
    * <p/>
    * This method actually does the reading on the OutputStream.  It will only do the read once.  
    * Afterwards, it will cache the result and return the cached result.
    *
    * @return
    */
   public abstract T getEntity();

   /**
    * Extract the response body with the provided type information
    * <p/>
    * This method actually does the reading on the OutputStream.  It will only do the read once.  
    * Afterwards, it will cache the result and return the cached result.
    *
    * @param type
    * @param genericType
    * @param <T2>
    * @return
    */
   public abstract <T2> T2 getEntity(Class<T2> type, Type genericType);

   /**
    * Extract the response body with the provided type information.  GenericType is a trick used to
    * pass in generic type information to the resteasy runtime.
    * <p/>
    * For example:
    * <pre>
    * List<String> list = response.getEntity(new GenericType<List<String>() {});
    * <p/>
    * <p/>
    * This method actually does the reading on the OutputStream.  It will only do the read once.  Afterwards, it will
    * cache the result and return the cached result.
    *
    * @param type
    * @param <T2>
    * @return
    */
   public abstract <T2> T2 getEntity(GenericType<T2> type);
}
All getEntity() methods are deferred until you invoke them. In other words, the response OutputStream is not read until you call one of these methods. The getEntity() method with no parameters can only be used if you have templated the ClientResponse within your method declaration. RESTEasy uses this generic type information to determine which media type the OutputStream is unmarshaled into. The getEntity() methods that take parameters let you specify the Object type the response should be marshaled into. This lets you dynamically extract the desired types at runtime. For example:
@Path("/")
public interface LibraryService {

   @GET
   @Produces("application/xml")
   ClientResponse<LibraryPojo> getAllBooks();
}
Include the LibraryPojo in ClientResponse's generic declaration so that the client proxy framework can unmarshal the HTTP response body.