First, we add 2 dependencies in our pom.xml
to be able to use Retrofit:
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>converter-jackson</artifactId>
<version>2.3.0</version>
</dependency>
Using Retrofit, we can easily get information from the API and transform it using Jackson into Java Objects.
First, we create an interface with a method for each call to the API we want to do:
public interface OpenAqApi {
@GET("countries")
Call<OpenAqCountriesResponse> listCountries();
}
Next, we create objects that correspond to the returned JSON structures:
@Getter
@Setter
@JsonIgnoreProperties(ignoreUnknown = true)
public class OpenAqCountriesResponse {
private List<OpenAqCountry> results;
}
@Getter
@Setter
@JsonIgnoreProperties(ignoreUnknown = true)
public class OpenAqCountry {
private String code;
private String name;
}
Note: We use @JsonIgnoreProperties(ignoreUnknown = true)
to avoid having to add properties in Java for JSON fields we are not interested in anyway.
Finally, we create an OpenAqServiceImpl
class that sets up Retrofit for our API:
@Component
public class OpenAqServiceImpl implements OpenAqService {
private final OpenAqApi api;
public OpenAqServiceImpl() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(interceptor).build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.openaq.org/v1/")
.addConverterFactory(JacksonConverterFactory.create())
.client(client)
.build();
api = retrofit.create(OpenAqApi.class);
}
@Override
public Set<OpenAqCountry> listCountries() {
try {
OpenAqCountriesResponse response = api.listCountries().execute().body();
if (response != null) {
return new HashSet<>(response.getResults());
} else {
return Collections.emptySet();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
Note: The current code also logs the HTTP requests and responses. For this to work, you need an additional dependency:
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>logging-interceptor</artifactId>
<version>3.8.0</version>
</dependency>
If you don’t want/need this logging, you can remove the dependency.
With all this plumbing in place, we can create our actual CountryServiceImpl
that is quite simple:
@Component
public class CountryServiceImpl implements CountryService {
private final OpenAqService service;
public CountryServiceImpl(OpenAqService service) {
this.service = service;
}
@Override
public Set<Country> getAllCountries() {
return service.listCountries().stream()
.map(openAqCountry -> new Country(openAqCountry.getCode(), openAqCountry.getName()))
.collect(Collectors.toSet());
}
}