Integrating Retrofit with RxJava
1. Overview
This article focuses on how to implement a simple RxJava-ready REST Client using Retrofit.
We’ll build an example application interacting with the GitHub API – using the standard Retrofit approach, and then we’ll enhance it using RxJava to leverage the advantages of Reactive Programming.
2. Plain Retrofit
Let’s first build an example with Retrofit. We’ll use the GitHub APIs to get a sorted list of all the contributors that have more than 100 contributions in any repository.
2.1. Maven Dependencies
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>converter-gson</artifactId>
<version>2.3.0</version>
</dependency>
For the latest versions, have a look at retrofit and converter-gson on Maven Central repository.
2.2. API Interface
public interface GitHubBasicApi {
@GET("users/{user}/repos")
Call<List> listRepos(@Path("user") String user);
@GET("repos/{user}/{repo}/contributors")
Call<List> listRepoContributors(
@Path("user") String user,
@Path("repo") String repo);
}
The listRepos() method retrieves a list of repositories for a given user passed as a path parameter.
The listRepoContributers() method retrieves a list of contributors for a given user and repository, both passed as path parameters.
2.3. Logic
class GitHubBasicService {
private GitHubBasicApi gitHubApi;
GitHubBasicService() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
gitHubApi = retrofit.create(GitHubBasicApi.class);
}
List<String> getTopContributors(String userName) throws IOException {
List<Repository> repos = gitHubApi
.listRepos(userName)
.execute()
.body();
repos = repos != null ? repos : Collections.emptyList();
return repos.stream()
.flatMap(repo -> getContributors(userName, repo))
.sorted((a, b) -> b.getContributions() - a.getContributions())
.map(Contributor::getName)
.distinct()
.sorted()
.collect(Collectors.toList());
}
private Stream<Contributor> getContributors(String userName, Repository repo) {
List<Contributor> contributors = null;
try {
contributors = gitHubApi
.listRepoContributors(userName, repo.getName())
.execute()
.body();
} catch (IOException e) {
e.printStackTrace();
}
contributors = contributors != null ? contributors : Collections.emptyList();
return contributors.stream()
.filter(c -> c.getContributions() > 100);
}
}
3. Integrating with RxJava
Retrofit lets us receive calls results with custom handlers instead of the normal Call object by using Retrofit Call adapters. This makes it possible to use RxJava Observables and Flowables here.
3.1. Maven Dependencies
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>adapter-rxjava</artifactId>
<version>2.3.0</version>
</dependency>
For the latest version please check adapter-rxjava in Maven central repository.
3.2. Register RxJava Call Adapter
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
3.3. API Interface
At this point, we can change the return type of interface methods to use Observable<…> rather than Call<…>. We may use other Rx types like Observable, Flowable, Single, Maybe, Completable.
Let’s modify our API interface to use Observable:
public interface GitHubRxApi {
@GET("users/{user}/repos")
Observable<List<Repository>> listRepos(@Path("user") String user);
@GET("repos/{user}/{repo}/contributors")
Observable<List<Contributer>> listRepoContributors(
@Path("user") String user,
@Path("repo") String repo);
}
3.4. Logic
class GitHubRxService {
private GitHubRxApi gitHubApi;
GitHubRxService() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
gitHubApi = retrofit.create(GitHubRxApi.class);
}
Observable<String> getTopContributors(String userName) {
return gitHubApi.listRepos(userName)
.flatMapIterable(x -> x)
.flatMap(repo -> gitHubApi.listRepoContributors(userName, repo.getName()))
.flatMapIterable(x -> x)
.filter(c -> c.getContributions() > 100)
.sorted((a, b) -> b.getContributions() - a.getContributions())
.map(Contributor::getName)
.distinct();
}
}
4. Conclusion
Comparing the code before and after using RxJava, we’ve found that it has been improved in the following ways:
-
Reactive – as our data now flows in streams, it enables us to do asynchronous stream processing with non-blocking back pressure
-
Clear – due to its declarative nature
-
Concise – the whole operation can be represented as one operation chain
All the code in this article is available over on GitHub.
The package com.baeldung.retrofit.basic contains the basic retrofit example while the package com.baeldung.retrofit.rx contains the retrofit example with RxJava integration.