back to all blogsSee all blog posts

MicroProfile Rest Client 2.0 - First Look

image of author
Andy McCright on Mar 24, 2021
Post available in languages:

The latest release of MicroProfile’s type-safe REST client has a lot of new and exciting features. In this post, we’ll take a look at some of the new features and how you can use them in Open Liberty, including:

Getting started

The MicroProfile Rest Client 2.0 implementation is new in Open Liberty 21.0.0.3 - so make sure you are using the latest version of Liberty. Next, you will need to add the following Maven dependency to your pom.xml:

<dependency>
    <groupId>org.eclipse.microprofile.rest.client</groupId>
    <artifactId>microprofile-rest-client-api</artifactId>
    <version>2.0</version>
    <scope>provided</scope>
</dependency>

or, if you use Gradle:

dependencies {
    compileOnly group: 'org.eclipse.microprofile.rest.client', name: 'microprofile-rest-client-api', version: '2.0'
}

Also, make sure to configure your Liberty server with the mpRestClient-2.0 feature in the server.xml:

<server>
  <featureManager>
    <feature>mpRestClient-2.0</feature>
    <!-- ... -->
  </featureManager>
  <!-- ... -->
</server>

That’s it! Now that we’ve got our development and deployment environments set up, it’s time to code!

Using QueryParamStyle to specify how collections of query parameters should be formatted

Rest Client interfaces can specify query parameters using the @QueryParam("paramName") annotation, but often a server will require that multi-valued query parameters must be formatted in a certain way. For example, suppose we have a client interface like:

@RegisterRestClient
public interface MyClient {
    @GET
    String multiValues(@QueryParam("myParam") List<String> values);
}

By default, if a caller invokes the client with multiValues(Arrays.asList("a", "b", "c")) the MP Rest Client will produce an HTTP request with multiple key/value pairs - something like: ?myParam=a&myParam=b&myParam=c.

Although most servers will handle that just fine, some servers might require the HTTP request to be a single key with a comma-separated list of values, like: ?myParam=a,b,c.

Still other servers will require array-like syntax, such as: ?myParam[]=a&myParam[]=b&myParam[]=c.

In order to support those other server types, you can now use the QueryParamStyle enum when building the client instance - for example:

MyClient client = RestClientBuilder.newBuilder()
                                   .queryParamStyle(QueryParamStyle.COMMA_SEPARATED)
                                   //...
                                   .build(MyClient.class);

Alternatively, you can declare the query parameter style through MP Config by using a property like:

com.mypkg.MyClient/mp-rest/queryParamStyle=ARRAY_PAIRS

The following table lists the QueryParamStyle enum values and provides an example of the corresponding output for each value.

Table 1. QueryParamStyle Options

Enum Value

Output Example

MULTI_PAIRS (default)

?myParam=a&myParam=b&myParam=c

COMMA_SEPARATED

?myParam=a,b,c

ARRAY_PAIRS

?myParam[]=a&myParam[]=b&myParam[]=c

Proxy server support

You might need to use a proxy server to access some RESTful endpoints. MicroProfile Rest Client 2.0 makes it easier and more portable to specify a proxy server with the new proxyAddress(host, port) method on the RestClientBuilder class. For example, suppose you need to access an endpoint via a proxy server at myproxy.xyz.com on port 1080. You could build your rest client instance with code like:

MyClient client = RestClientBuilder.newBuilder()
                                   .proxyAddress("myproxy.xyz.com", 1080)
                                   //...
                                   .build(MyClient.class);

Alternatively, you can specify the proxy address via MP Config with a property like:

com.mypkg.MyClient/mp-rest/proxyAddress=myproxy.xyz.com:1080

Note that for portability, this approach to setting the proxy server host and port is preferred to using vendor-specific properties such as com.ibm.ws.jaxrs.client.proxy.host and com.ibm.ws.jaxrs.client.proxy.port, though these properties will still work. For proxy authentication, you can still use the com.ibm.ws.jaxrs.client.proxy.username and com.ibm.ws.jaxrs.client.proxy.password properties. For example:

MyClient client = RestClientBuilder.newBuilder()
                                   .proxyAddress("myproxy.xyz.com", 1080)
                                   .property("com.ibm.ws.jaxrs.client.proxy.username", "andymc12")
                                   .property("com.ibm.ws.jaxrs.client.proxy.password", "12345") //same as my luggage! :)
                                   //...
                                   .build(MyClient.class);

Automatically following redirects

If a RESTful resource has been relocated, often the HTTP response code will be in the 300 range and will indicate the new location. Rather than handling the 3XX response and manually issuing a new request, MP Rest Client 2.0 allows rest client instances to automatically follow redirects. You can configure a client to automatically follow redirects either programmatically, when you build the client instance, or via MP Config. Here is an example of configuring auto-redirect via the RestClientBuilder API:

MyClient client = RestClientBuilder.newBuilder()
                                   .followRedirects(true)
                                   //...
                                   .build(MyClient.class);

And here is how you would configure it via MP Config:

com.mypkg.MyClient/mp-rest/followRedirects=true

Support for Server Sent Events (SSEs)

Server Sent Events, part of the HTML 5 spec, enable a server to push data to a client asynchronously via events, over HTTP. The JAX-RS 2.1 spec enabled SSE support for both the client and server. Now you can consume SSE events from the type-safe MP Rest Client.

The MP Rest Client specification uses the Reactive Streams APIs to consume events. A client interface capable of consuming SSEs looks something like this:

@RegisterRestClient
public interface SseClient {
    @GET
    @Path("/path/sse")
    @Produces(MediaType.SERVER_SENT_EVENTS)
    Publisher<String> getStrings();
    @GET
    @Path("/path/sse2")
    @Produces(MediaType.SERVER_SENT_EVENTS)
    Publisher<InboundSseEvent> getEvents();
}

First, the method (or interface) must be annotated with @Produces(MediaType.SERVER_SENT_EVENTS) to indicate that it expects the server to produce SSEs. Next, the method’s return type must be org.reactivestreams.Publisher. The generic type can be javax.ws.rs.sse.InboundSseEvent (from JAX-RS), a primitive, a String, or a complex type. Complex types can only be used if;

1) the server only sends one type of event (e.g. only sends WeatherEvents - then Publisher<WeatherEvent> would be applicable)

and

2) there is a registered entity provider capable of converting the events (e.g. MessageBodyReader<WeatherEvent>).

In most cases, if the remote server sends events using JSON, you can enable the jsonb-1.0 feature in your Liberty server, which will automatically register a JSON-B-based entity provider.

Once you invoke one of these methods, you can register one or more Subscriber instances to the Publisher. Each subscriber will be notified on receipt of a new event or if the connection to the server has been closed.

Summary

MicroProfile Rest Client 2.0 has some powerful new features that are useful for building cloud native applications. You can read more about these updates on the MP Rest Client 2.0 release page.

MicroProfile Rest Client 2.0 is part of the larger MicroProfile 4.0 release. If you’d like to learn more about the other technologies in MicroProfile 4.0, check out this deep dive blog post.

As always, let us know if you have any questions with this new feature. Thanks for checking it out!