# MicroProfile Rest Client

As the microservices style of system architecture (see, for example, Microservices by Martin Fowler) gains increasing traction, new API standards are coming along to support it. One set of such standards comes from the Microprofile Project supported by the Eclipse Foundation, and among those is one, MicroProfile Rest Client, of particular interest to RESTEasy and JAX-RS. In fact, it is intended to be based on, and consistent with, JAX-RS, and it includes ideas already implemented in RESTEasy. For a more detailed description of MicroProfile Rest Client, see https://github.com/eclipse/microprofile-rest-client. In particular, the API code is in https://github.com/eclipse/microprofile-rest-client/tree/master/api. and the specification is in https://github.com/eclipse/microprofile-rest-client/tree/master/spec.

## Client proxies

One of the central ideas in MicroProfile Rest Client is a version of distributed object communication, a concept implemented in, among other places, CORBA, Java RMI, the JBoss Remoting project, and RESTEasy. Consider the resource

    @Path("resource")
    public class TestResource {

       @Path("test")
       @GET
       String test() {
          return "test";
       }
    }

The JAX-RS native way of accessing `TestResource` looks like

    Client client = ClientBuilder.newClient();
    String response = client.target("http://localhost:8081/test").request().get(String.class);

The call to `TestResource.test()` is not particularly onerous, but calling `test()` directly allows a more natural syntax. That is exactly what Microprofile Rest Client supports:

    @Path("resource")
    public interface TestResourceIntf {

       @Path("test")
       @GET
       public String test();
    }

    TestResourceIntf service = MicroprofileClientBuilderResolver.instance()
                                  .newBuilder()
                                  .baseUrl(http://localhost:8081/))
                                  .build(TestResourceIntf.class);
    String s = service.test();

The first four lines of executable code are spent creating a proxy, `service`, that implements `TestResourceIntf`, but once that is done, calls on `TestResource` can be made very naturally in terms of `TestResourceIntf`, as illustrated by the call `service.test()`.

Beyond the natural syntax, another advantage of proxies is the way the proxy construction process quietly gathers useful information from the implemented interface and makes it available for remote invocations. Consider a more elaborate version of `TestResourceIntf`:

    @Path("resource")
    public interface TestResourceIntf2 {

       @Path("test/{path}")
       @Consumes("text/plain")
       @Produces("text/html")
       @POST
       public String test(@PathParam("path") String path, @QueryParam("query") String query, String entity);
    }

Calling `service.test("p", "q", "e")` results in an HTTP message that looks like

    POST /resource/test/p/?query=q HTTP/1.1
    Accept: text/html
    Content-Type: text/plain
    Content-Length: 1

    e

The HTTP verb is derived from the `@POST` annotation, the request URI is derived from the two instances of the `@Path` annotation (one on the class, one on the method) plus the first and second parameters of `test()`, the Accept header is derived from the `@Produces` annotation, and the Content-Type header is derived from the `@Consumes` annotation,

Using the JAX-RS API, `service.test("p", "q", "e")` would look like the more verbose

    Client client = ClientBuilder.newClient();
    String response = client.target("http://localhost:8081/resource/test/p")
                         .queryParam("query", "q")
                         .request()
                         .accept("text/html")
                         .post(Entity.entity("e", "text/plain"), String.class);

One other basic facility offered by MicroProfile Rest Client is the ability to configure the client environment by registering providers:

    TestResourceIntf service = MicroprofileClientBuilderResolver.instance()
                                  .newBuilder()
                                  .baseUrl(http://localhost:8081/))
                                  .register(MyClientResponseFilter.class)
                                  .register(MyMessageBodyReader.class)
                                  .build(TestResourceIntf.class);

Naturally, the registered providers should be relevant to the client environment, rather than, say, a `ContainerResponseFilter`.

So far, the MicroProfile Rest Client should look familiar to anyone who has used the RESTEasy client proxy facility (Section ""RESTEasy Proxy Framework"). The construction in the previous listing would look like

    ResteasyClient client = (ResteasyClient) ResteasyClientBuilder.newClient();
    TestResourceIntf service = client.target("http://localhost:8081/")
                                  .register(MyClientResponseFilter.class)
                                  .register(MyMessageBodyReader.class)
                                  .proxy(TestResourceIntf.class);

in RESTEasy.

## Beyond RESTEasy

There are a few concepts in MicroProfile Rest Client that do not appear in RESTEasy.

### Declarative registration of providers

In addition to programmatic registration of providers as illustrated above, it is also possible to register providers declaratively with annotations introduced in MicroProfile Rest Client. In particular, providers can be registered by adding the `org.eclipse.microprofile.rest.client.annotation.RegisterProvider` annotation to the target interface:

    @Path("resource")
    @RegisterProvider(MyClientResponseFilter.class)
    @RegisterProvider(MyMessageBodyReader.class)
    public interface TestResourceIntf2 {

       @Path("test/{path}")
       @Consumes("text/plain")
       @Produces("text/html")
       @POST
       public String test(@PathParam("path") String path, @QueryParam("query") String query, String entity);
    }

Declaring `MyClientResponseFilter` and `MyMessageBodyReader` with annotations eliminates the need to call `RestClientBuilder.register()`.

### ResponseExceptionMapper

The `org.eclipse.microprofile.rest.client.ext.ResponseExceptionMapper` is the client side inverse of the `javax.ws.rs.ext.ExceptionMapper` defined in JAX-RS. That is, where `ExceptionMapper.toResponse()` turns an `Exception` thrown during server side processing into a `Response`, `ResponseExceptionMapper.toThrowable()` turns a `Response` received on the client side with an HTTP error status into an `Exception`. `ResponseExceptionMapper`s can be registered in the same manner as other providers, that is, either programmatically or declaratively. In the absence of a registered `ResponseExceptionMapper`, a default `ResponseExceptionMapper` will map any response with status >= 400 to a `WebApplicationException`.

### Proxy injection by CDI

MicroProfile Rest Client mandates that implementations must support CDI injection of proxies. At first, the concept might seem odd in that CDI is more commonly available on the server side. However, the idea is very consistent with the microservices philosophy. If an application is composed of a number of small services, then it is to be expected that services will often act as clients to other services.

CDI (Contexts and Dependency Injection) is a fairly rich subject and beyond the scope of this Guide. For more information, see JSR 365: Contexts and Dependency Injection for JavaTM 2.0 (the specification), Java EE 7 Tutorial, or WELD - CDI Reference Implementation.

The fundamental thing to know about CDI injection is that annotating a variable with `javax.inject.Inject` will lead the CDI runtime (if it is present and enabled) to create an object of the appropriate type and assign it to the variable. For example, in

       public interface Book {
          public String getTitle();
          public void setTitle(String title);
       }

       public class BookImpl implements Book {

          private String title;

          @Override
          public String getTitle() {
             return title;
          }

          @Override
          public void setTitle(String title) {
             this.title = title;
          }
       }

       public class Author {

          @Inject private Book book;

          public Book getBook() {
             return book;
          }
       }

The CDI runtime will create an instance of `BookImpl` and assign it to the private field `book` when an instance of `Author` is created;

In this example, the injection is done because `BookImpl` is assignable to `book`, but greater discrimination can be imposed by annotating the interface and the field with qualifier annotations. For the injection to be legal, every qualifier on the field must be present on the injected interface. For example:

       @Qualifier
       @Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
       @Retention(RetentionPolicy.RUNTIME)
       public @interface Text {}

       @Qualifier
       @Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
       @Retention(RetentionPolicy.RUNTIME)
       public @interface Graphic {}

       @Text
       public class TextBookImpl extends BookImpl { }

       @Graphic
       public class GraphicNovelImpl extends BookImpl { }

       public class Genius {

          @Inject @Graphic Book book;
       }

Here, the class `TextBookImpl` is annotated with the `@Text` qualifier and `GraphicNovelImpl` is annotated with `@Graphic`. It follows that an instance of `GraphicNovelImpl` is eligible for assignment to the field `book` in the `Genius` class, but an instance of `TextBookImpl` is not.

Now, in MicroProfile Rest Client, any interface that is to be managed as a CDI bean must be annotated with `@RegisterRestClient`:

       @Path("resource")
       @RegisterProvider(MyClientResponseFilter.class)
       public static class TestResourceImpl {

          @Inject TestDataBase db;

          @Path("test/{path}")
          @Consumes("text/plain")
          @Produces("text/html")
          @POST
          public String test(@PathParam("path") String path, @QueryParam("query") String query, String entity) {
             return db.getByName(query);
          }
       }

       @Path("database")
       @RegisterRestClient
       public interface TestDataBase {

          @Path("")
          @POST
          public String getByName(String name);
       }

Here, the MicroProfile Rest Client implementation creates a proxy for a `TestDataBase` service, allowing easy access by `TestResourceImpl`. Notice, though, that there's no indication of where the `TestDataBase` implementation lives. That information can be supplied externally with the system variable

                <fqn of TestDataBase>/mp-rest/url=<URL>

For example,

    com.bluemonkeydiamond.TestDatabase/mp-rest/url=https://localhost:8080/webapp

indicates that an implementation of `com.bluemonkeydiamond.TestDatabase` can be accessed at https://localhost:8080/webapp.