Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[open-measured-data-wg] [MDM Hackathon]

Dear colleagues,

As discusses on the later hours of the first day of the MDM Hackathon, these are some additional technologies that can be used in tandem to consume REST APIs using the observer pattern

Retrofit makes it easy to consume REST APIs without having to configure an HttpClient by hand, nor having to define a marshalling (XML/JSON) option by hand.
This library works for Java only.

The Java extension to http://reactivex.io/ . Provides and implementation of the Observer pattern.

Both can be used to consume REST URLs. Using the GitHub API as an example, the consumer could look like this (there will be some code in the following paragraphs to serve as inspiration):

@Inject private Github github;

public void load() {
Observable<Repository> observable = github.repositories(model.getOrganization());
if (model.getLimit() > 0) {
observable = observable.take(model.getLimit());
}
model.setSubscription(observable
.timeout(10, TimeUnit.SECONDS)
.doOnSubscribe(() -> model.setState(RUNNING))
.doOnTerminate(() -> model.setState(READY))
.subscribe(
model.getRepositories()::add,
Throwable::printStackTrace));
}
the producer of results from the REST API could look like this

public class DefaultGithub implements Github {
@Inject private GithubAPI api;

@Nonnull
@Override
public Observable<Repository> repositories(final @Nonnull String name) {
requireNonBlank(name, "Argument 'name' must not be blank");

return paginatedObservable(
() -> api.repositories(name),
(Links links) -> api.repositoriesPaginate(links.next()));
}
}
which consumes REST results defined in a Retrofit enabled API

public interface GithubAPI {
    @Nonnull
@GET("/orgs/{name}/repos")
Observable<Response<List<Repository>>> repositories(@Nonnull @Path("name") String name);

@Nonnull
@GET
Observable<Response<List<Repository>>> repositoriesPaginate(@Nonnull @Url String url);
}
the final link to the puzzle is the composition of paginated results as a single Observable
public final class ObservableUtils {
private ObservableUtils() {
// prevent instantiation
}

@Nonnull
public static <T> Observable<T> paginatedObservable(@Nonnull final FirstPageSupplier<T> firstPage, @Nonnull final NextPageSupplier<T> nextPage) {
requireNonNull(firstPage, "Argument 'firstPage' must not be null");
requireNonNull(nextPage, "Argument 'nextPage' must not be null");

return processPage(nextPage, firstPage.get());
}

private static <T> Observable<T> processPage(@Nonnull final NextPageSupplier<T> supplier, @Nonnull Observable<Response<List<T>>> items) {
return items.flatMap(response -> {
Links links = Links.of(response.headers().get("Link"));
Observable<T> currentPage = Observable.from(response.body());
if (links.hasNext()) {
return currentPage.concatWith(processPage(supplier, supplier.get(links)));
}
return currentPage;
});
}

public interface FirstPageSupplier<T> {
@Nonnull
Observable<Response<List<T>>> get();
}

public interface NextPageSupplier<T> {
@Nonnull
Observable<Response<List<T>>> get(@Nonnull Links links);
}
}
Cheers,
Andres
 
Andres Almiray
Canoo Engineering AG
Kirschgartenstrasse 5
CH-4051 Basel

Tel: +41 61 228 94 44
Fax: +41 61 228 94 49

andres.almiray@xxxxxxxxx
http://www.canoo.com


Back to the top