# Client Framework

## Fluent interface

The two principal client side classes in Resteasy 2 are `ClientRequest` and `ClientResponse`:

    ClientRequest request = new ClientRequest("http://localhost:8081/test");
    request.body("text/plain", "hello world");
    ClientResponse<?> response = request.post();
    String result = response.getEntity(String.class);

`ClientRequest` holds the target URL and entity, if any. `ClientResponse` holds the response entity, which can be extracted by the getEntity() method.

In JAX-RS 2.0, these classes are replaced by four classes that support a fluent call pattern: `Client`, `WebTarget`, `Invocation.Builder`, and `Response`:

    Client client = ClientBuilder.newClient();
    WebTarget target = client.target("http://localhost:8081/test");
    Invocation.Builder builder = target.request();
    Entity<String> entity = Entity.entity("hello world", "text/plain");
    Response response = builder.post(entity);
    String result = response.readEntity(String.class);

The invocation process begins with `Client`, whose primary responsibility is to create a `WebTarget`. `Client`s are somewhat expensive to build, so it often makes sense to reuse a `Client` to create multiple `WebTarget`s.

Resteasy extends `ClientBuilder` and `Client` with methods that allow the registration of providers:

    static class TestWriter implements MessageBodyWriter<String>
    {
       @Override
       public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType)
       {
          return false;
       }

       @Override
       public long getSize(String t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType)
       {
          return 0;
       }

       @Override
       public void writeTo(String t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType,
             MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream)
             throws IOException, WebApplicationException
       {
          //
       }
    }

    ResteasyClientBuilder clientBuilder = new ResteasyClientBuilder();
    Client client = clientBuilder.register(TestWriter.class).build();

All `Client`s created by that `ResteasyClientBuilder`, and all invocations on all `WebTarget`s created by those `Client`s, will have `TestWriter` available.

`WebTarget`, as its name implies, constructs and holds a URL which targets a server side resource. It has various options for extending and manipulating URIs:

    WebTarget target = client.target("http://localhost:8081/test/{index}");
    WebTarget target1 = target.resolveTemplate("index", "1");
    WebTarget target2 = target.resolveTemplate("index", "2");

Here, two new `WebTarget`s are created from the original target, each with a different ending path segment. Query and matrix parameters can also be appended:

    WebTarget target3 = target2.queryParam("x", "y");

Here, target3 targets "http://localhost:8081/test/2?x=y".

Resteasy also extends `WebTarget` with the ability to register providers:

    Client client = ClientBuilder.newClient();
    String url = "http://localhost:8081/test/{index}";
    WebTarget target = client.target(url).register(TestWriter.class);
    WebTarget target1 = target.resolveTemplate("index", "1");
    WebTarget target2 = target.resolveTemplate("index", "2");
    WebTarget target3 = target2.queryParam("x", "y");

Here, `TestWriter` is available to all invocations on target1, target2, and target3.

`Invocation.Builder` plays a role similar to the old `ClientRequest`:

    Response response = builder.header("User-Agent", "Mozilla/5.0").get();

or

    String s = builder.header("User-Agent", "Mozilla/5.0").get(String.class);

Finally, note that `Response`, unlike the old `ClientResponse<T>`, is not a generic type, so it is necessary to give a type when extracting a response entity:

    String result = response.readEntity(String.class);

Note. `Response.getEntity()` still exists, but it plays a different role, which could easily lead to bugs. It is necessary to call `readEntity()` to extract the response entity. If `getEntity()` is called instead, it will return null.

Note. Unlike the old `getEntity()`, `readEntity()` is not idempotent. Once it is called, the response is closed, and subsequent calls will throw an `IllegalStateException`. This behavior can be circumvented by calling `Response.bufferEntity()` before calling `readEntity()`. I.e., this will work:

    response.bufferEntity();
    System.out.println(response.readEntity(String.class));
    System.out.println(response.readEntity(String.class));

## Client proxies

The client framework in Resteasy 2 included a facility for interacting with JAX-RS resources through client side POJOs, not unlike the Java RMI facility:

    @Path("/test")
    public static interface TestResource
    {
       @GET
       @Produces("text/plain")
       public String test();
    }

    public void testProxy() throws Exception
    {
       String url = "http://localhost:8081";
       TestResource pojo = ProxyFactory.create(TestResource.class, url);
       String result = pojo.test();

This technique avoids a lot of complications, but, perhaps because it is perceived as not being in the RESTful spirit, it is not part of the JAX-RS 2.0 client framework. It still exists in Resteasy 3, but in a re-worked form that fits into the official client framework. Now, a proxy is created by a call to `ResteasyWebTarget.proxy()`:

    Client client = ClientBuilder.newClient();
    String url = "http://localhost:8081";
    ResteasyWebTarget target = (ResteasyWebTarget) client.target(url);
    TestResource pojo = target.proxy(TestResource.class);
    String result = pojo.test();

## Client side error handling

Resteasy 2 had two facilities for handling errors on the client side.

An instance of an `org.jboss.resteasy.client.core.ClientErrorInterceptor` could be registered to handle exceptions thrown during a proxied call. Also, an instance of an `org.jboss.resteasy.client.exception.mapper.ClientExceptionMapper` could be registered to map exceptions thrown during a proxied call. A default `ClientExceptionMapper` was installed that mapped exceptions thrown by the HttpClient transport layer to Resteasy specific analogs. For example, an `org.apache.http.client.ClientProtocolException` would be mapped to an `org.jboss.resteasy.client.exception.ResteasyClientProtocolException`.

These two facilities do not exist in Resteasy 3. Instead, the JAX-RS 2.0 specification mandates the use of `javax.ws.rs.ProcessingException` and `javax.ws.rs.client.ResponseProcessingException`. In particular, exceptions thrown while processing a request should be mapped to a `ProcessingException`, and exceptions thrown while processing a response should be mapped to a `ResponseProcessingException`.

For example, the `ProcessingException` javadoc lists possible conditions leading to a `ProcessingException:`

- failures in filter or interceptor chain execution
- errors caused by missing message body readers or writers for the particular Java type and media type combinations
- propagated `java.io.IOException`s thrown by `javax.ws.rs.ext.MessageBodyReader`s and `javax.ws.rs.ext.MessageBodyWriter`s during entity serialization and de-serialization

Note that `ProcessingException` and `ResponseProcessingException` represent internal problems. If the client side receives a response with status codes 3xx, 4xx or 5xx, it will map the response to an instance of `javax.ws.rs.WebApplicationException` or one of its subclasses.

## Maven considerations

In Resteasy 2, the client framework lives in the resteasy-jaxrs module. In Resteasy 3, it has its own module, resteasy-client:

    <dependency>
       <groupId>org.jboss.resteasy</groupId>
       <artifactId>resteasy-client</artifactId>
       <version>${project.version}</version>
    </dependency>