mercadolibre/java-restclient

Name: java-restclient

Owner: MercadoLibre

Description: A lightweight REST client implementation for Java 1.7+.

Created: 2017-05-22 20:38:58.0

Updated: 2018-04-20 17:32:13.0

Pushed: 2017-07-01 02:17:48.0

Homepage:

Size: 858

Language: Java

GitHub Committers

UserMost Recent Commit# Commits

Other Committers

UserEmailMost Recent Commit# Commits

README

Rest Client

Lightweight REST client implementation for Java 1.7+.

For questions and support please contact services@mercadolibre.com

Contents

Dependencies

You must define the repository resolver

ository>
<id>java-restclient-mvn-repo</id>
<url>https://raw.github.com/mercadolibre/java-restclient/mvn-repo/</url>
<snapshots>
    <enabled>true</enabled>
    <updatePolicy>always</updatePolicy>
</snapshots>
pository>

and the dependency itself

endency>
<groupId>com.mercadolibre.restclient</groupId>
<artifactId>restclient-default</artifactId>
<version>0.0.10</version>
pendency>

Building a REST Client

A RestClient instance uses a collection of RESTPool to route its requests.

So, first you have to build as many instances of RESTPool as you need using its builder. Please take also a moment to read about RESTPool concept.

Pool aPool = RESTPool.builder()
.withName("my_pool")
.build();

Once you have built all of your pool instances, you can build your RestClient instance. Every RestClient instance also contains a default RESTPool implementation, with typical parameters. Itīll be used when no pool is defined in a request.

Client restClient = RestClient.builder()
.withPool(aPool, bPool)
.build();

This instance is thread safe and it should be shared across resources in your application. For typical uses, youd only need just one instance of RestClient in your entire application.

Understanding RESTPool

A RESTPool is a collection of HTTP resource definitions, itīs not just a connection pool.
You can think of it as a separate client, intended to handle some group of resources and that is part of a RestClient, which instead is intended to bind many RESTPool instances and abstract HTTP calls.
It groups together connection pool definitions (max connections, socket timeout, etc) with high level features such as proxy, basic authentication, interceptors and so on.

For every request you make you must explicitly specify which RESTPool should be used, in case you donīt want your request to be handled by the provided default RESTPool.

Some typical uses are

Basic Usage

Basic Requests

You can use your RestClient instance right away, by routing requests through its default pool.

onse response = restClient.get("http://yourdomain.com/resource");

In a similar way, you can add custom headers to your request

ers headers = new Headers().add("Content-Type", "text/plain");
onse response = restClient.get("http://yourdomain.com/resource", headers);

In case you want to send a request with body, you should do it as a byte array.

[] body = "{\"text\":\"hello\"}".getBytes();
onse response = restClient.post("http://yourdomain.com/resource", body);

Headers are allowed in a similar way

ers headers = new Headers().add("Content-Type", "text/plain");
[] body = "hello".getBytes();
onse response = restClient.post("http://yourdomain.com/resource", headers, body);
Response Handling

A Response object provides methods to get HTTP response data

onse response = restClient.get("http://yourdomain.com/resource");

status = response.getStatus();
headers = response.getHeaders();
[] body = response.getBytes();

Also, if you have a Serializer registered for current Content-Type, you can get its marshaled data as Object or as another you provide.

onse response = restClient.get("http://yourdomain.com/get_item");

ct body = response.getData();
 body = response.getData(Item.class);
Default RestClient

In case you would like to route your requests only through the default pool, you could use the provided RestClient default implementation.

onse response = RestClient.getDefault().get("http://yourdomain.com/resource");
Defaults List

When you use a default implementation the following features apply

Advanced Usage

Customizing Requests

It's possible to specify many request scoped features for sync and async calls. Many of then can also be specified poolwise.

Specifying a Pool
onse response = restClient.withPool(aPool).get("http://yourdomain.com/resource");
Adding a Proxy
onse response = restClient.withProxy("http://proxy",80).get("http://yourdomain.com/resource");
Adding Basic Authentication
onse response = restClient.withAuthentication("http://auth", 80, "user", "pass").get("http://yourdomain.com/resource");
Using Interceptors

An interceptor applies over a request, just before sending it; or over a response, right after receiving it. In both cases, they are stored in a deque, so you can easily manage the order in which they are applied.

To intercept a request, just implement a RequestInterceptor, or maybe one of the provided may help.

onse response = restClient.withInterceptorFirst(new YourRequestInterceptor()).get("http://yourdomain.com/resource");
ava
onse response = restClient.withInterceptorLast(new YourRequestInterceptor()).get("http://yourdomain.com/resource");

As for response interceptors, provide your own by implementing ResponseInterceptor.

onse response = restClient.withInterceptorFirst(new YourResponseInterceptor()).get("http://yourdomain.com/resource");
ava
onse response = restClient.withInterceptorLast(new YourResponseInterceptor()).get("http://yourdomain.com/resource");
Downloading Data to a Stream

You can provide an OutputStream where you want your data to be streamed. Notice that trying to also fetch data from associated response will be null. Remember to close stream upon completion.

onse response = restClient.get("http://yourdomain.com/resource", yourOutputStream);
Uploading Multipart Data

To upload multipart data, just add parts and make your request.

onse response = restClient
.withPart(aPart)
.withPart(bPart)
.post("http://yourdomain.com/resource");
Retry Strategies

You may define a retry strategy that specifies when a response is to be considered a failure, and an action thatll be run on each retry call.

We provide two basic strategies

Simple Retry Strategy

Itll just retry for a fixed number of times and wait for a fixed interval between runs

onse response = restClient
.withRetryStrategy(new SimpleRetryStrategy(MAX_RETRIES, WAIT_MS))
.get("http://yourdomain.com/resource");
Exponential Backoff Retry Strategy

Itīll increase wait time between retries between a min and a max value, growing exponentially between runs

onse response = restClient
.withRetryStrategy(new ExponentialBackoffRetryStrategy(MIN_MS, MAX_MS))
.get("http://yourdomain.com/resource");

Using Caches

We provide local and memcached cache implementations, thatll cache requests based on their Cache-Control header info.

All cache implementations can be chained, to be made multilevel. Every constructor has a version with the next level as the last argument.

For more information about Cache-Control you can take a look here and here.

Local Cache
Cache cache = new RESTLocalCache("my_cache", MAX_ELEMENTS);
onse response = restClient
.withCache(cache)
.get("http://yourdomain.com/resource");
Memcached Cache

In this case, you must provide a wrapper over your Memcached client

MemcachedClient client = new MyRESTMemcachedClient();
Cache cache = new RESTMemcachedCache("my_cache", client);

onse response = restClient
.withCache(cache)
.get("http://yourdomain.com/resource");

Async API

Asynchronous calls are handled similar to their synchronous counterpart, we just return a Future<Response> as a promise of call completion. A RestException is raised if request could not be built up, but every other exception will be wrapped around Futureīs ExecutionException upon get.

Caching and retries are handled under the hood. Both of them, as well as call themselves, are handled in a non blocking way.

As an example, an async GET could be made as

re<Response> response = restClient.asyncGet("http://yourdomain.com/resource");
status = response.get().getStatus();

There's also the possibility to specify an instance of Callback<Response> as a completion callback for current requst, instead of getting a Future instance.

Client.asyncGet("http://yourdomain.com/resource", myCallback);

Serializers

When you obtain a Response, you can get its raw data as a byte array by calling its getBytes() method. Also you can parse its content according to received Content-Type header, if you previously had registered a serializer capable of handling it.

alizers.register(ContentType.APPLICATION_JSON, mySerializer);

A Jackson based JSON parser is shipped with restclient-default package, as well as parsers for usual contents. You can override them by registering a custom Serializer as shown.

Logging

We use slf4j as a common interface for different logging implementations. If you want to collect Rest Client logs, first you must add the binding for your current logging implementation.

For example, if you use log4j 1.2.x, you should add

endency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
pendency>

Then you should specify which level you want to apply to restClientLogger logger.

Mocks

We provide a mock server for testing, which is immediately available in test environment. You can specify which response should be given for a specific request, or if the client should fail instead.
You can forget about mock and cache cleanup after each test, if you make your tests extend from RestClientTestBase.

Dependency
endency>
<groupId>com.mercadolibre.restclient</groupId>
<artifactId>restclient-core</artifactId>
<version>0.0.10</version>
<classifier>tests</classifier>
<scope>test</scope>
pendency>
Usage Example

In this simple example, we add a response with status code 200 and a plain text response body for any GET to “http://localhost/endpoint””

Response.builder()
.withURL("http://localhost/endpoint")
.withMethod(GET)
.withStatusCode(200)
.withResponseHeader(ContentType.HEADER_NAME, ContentType.TEXT_PLAIN.toString())
.withResponseHeader("Cache-Control", "max-age=3600")
.withResponseBody("ok")
.build();

A simple in-memory cache is also available for testing purposes.


This work is supported by the National Institutes of Health's National Center for Advancing Translational Sciences, Grant Number U24TR002306. This work is solely the responsibility of the creators and does not necessarily represent the official views of the National Institutes of Health.