Keddit — Part 6: API — Retrofit & Kotlin

Juan Ignacio Saravia
AndroidPub
Published in
6 min readApr 2, 2016

Content

Part 6: API — Retrofit & Kotlin

Now it’s time to make a real API call and demonstrate that our abstraction with RxJava really works! and of course to show some real news in the App :)

This is how we are going to pass from Mock data to Real data:

Mock Data vs Real Data

We didn’t implemented the infinite scroll yet but at least we are going to see 10 news and at the end the loader ready for the next Part.

Reddit API

Let’s review a little bit the API that we are going to consume from Reddit. The idea is to request the Reddit’s TOP news to be shown in the App.

Request URL

The URL that we are going to consume is the following:

www.reddit.com/top.json?limit=10

You are able to paste this into your browser and see something like this:

JSON Response

As you can see the returned response is in JSON format. A better way to analyse the content is using a Json parser like Json Editor Online (http://www.jsoneditoronline.org/) which is an excellent online tool. So now we can see it in a better way:

Here there are 3 things that we will care about it:

  • children: Is the news’ list paginated by 10 items (as we requested in the query string) and each children has details about the news (name, image, author, etc).
  • after: It allows you to perform pagination with this Reddit API. “after” will bring you the next 10 items by calling: “/top.json?after=t3_4cdt7v”.
  • before: The same as “after” but to navigate back.

A children contains a lot of information:

But we are going to pick just some of them.

Retrofit

Is a type-safe HTTP client for Android and Java

Retrofit is an incredible easy to use library that turns your HTTP API into a Java (Kotlin) interface. We are going to use it to consume the Reddit API.

Dependency

We need to add the Retrofit dependency:

compile "com.squareup.retrofit2:retrofit:2.0.0"

JSON Converter

Also we need to indicate to Retrofit which converter it should use to convert a JSON response into a Java (Kotlin) class and I’m going to use Moshi as it has better performance than Gson:

compile "com.squareup.retrofit2:converter-moshi:2.0.0"

Here you have a great video from Jake Warthon explaining about Moshi and why Moshi works better than others with Retrofit.

In summary, Moshi knows about Okio and its API, so it takes advantages of Okio buffers and read and write content directly into this buffer without requiring it to allocate extra memory for this process (to convert the response data stream into Java code and viceversa). In same way, Moshi is like a higher level API of Okio API so you are in fact just adding a simpler API on top of Okio.

API Model: Kotlin Classes

We need to create some classes in order to convert our Json response into Kotlin classes. If we do this in Java we will end up creating big Java files with getters and setters to do this but as we are using Kotlin we can take advantage of this and represent all these classes really easily. It’s so clean and concise that I can paste here all the code to represent these classes :)

class RedditNewsResponse(val data: RedditDataResponse)

class RedditDataResponse(
val children: List<RedditChildrenResponse>,
val after: String?,
val before: String?
)

class RedditChildrenResponse(val data: RedditNewsDataResponse)

class RedditNewsDataResponse(
val author: String,
val title: String,
val num_comments: Int,
val created: Long,
val thumbnail: String,
val url: String
)

Here we are mapping the previous model that we reviewed with Kotlin classes and with this 4 classes we are ready!

API Interface

I created a Kotlin file called RedditApi and it looks like this:

import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Query
interface RedditApi {
@GET("/top.json")
fun getTop(@Query("after") after: String,
@Query("limit") limit: String)
: Call<RedditNewsResponse>;
}

We defined here a synchronous API that will receive the “after” and “limit” query string. The return type is “Call<RedditNewsResponse>”, this Call class will allow us to execute the request and know if the request was successful or not, also to extract the response data with the given generic type, in this case, the new defined Kotlin class RedditNewsResponse.

Rest API

Now we are going to move Retrofit initialization into a new class called “RestAPI.kt”.

In Kotlin classes you are able to initialize your class in a body block with the init keyword. Here we are going to use it to initialize our RedditApi:

private val redditApi: RedditApi

init {
val retrofit = Retrofit.Builder()
.baseUrl("https://www.reddit.com")
.addConverterFactory(MoshiConverterFactory.create())
.build()

redditApi = retrofit.create(RedditApi::class.java)
}
  1. init block: Kotlin class initializer block.
  2. “.addConverterFactory(MoshiConverterFactory.create())”: Setting the Moshi converter.
  3. “RedditApi::class.java”: This syntax allows you to get the Java Class instance corresponding to the given KClass instance. A KClass is an interface that represents a class and provides introspection capabilities.

getNews:

And also we provide a function to consume the API and request the news:

fun getNews(after: String, limit: String): Call<RedditNewsResponse>{
return redditApi.getTop(after, limit)
}

Commit:

https://github.com/juanchosaravia/KedditBySteps/commit/8295dfa18896a3ac18757e4c026fa1e7d5ec1600

IMPORTANT

Make sure to add this permission in the AndroidManifest.xml file:

<uses-permission android:name="android.permission.INTERNET" />

NewsManager: Call the Api!

We are going to use default parameters to initialize our RestApi class in this way:

class NewsManager(private val api: RestAPI = RestAPI()) {
...
}

Also updating the Observable definition to call this Api and perform the request:

subscriber ->
val callResponse = api.getNews("", limit)
val response = callResponse.execute()

if (response.isSuccessful) {
val news = response.body().data.children.map {
val item = it.data
RedditNewsItem(item.author, item.title, item.num_comments,
item.created, item.thumbnail, item.url)
}
subscriber.onNext(news)
subscriber.onCompleted()
} else {
subscriber.onError(Throwable(response.message()))
}
  1. callResponse.execute(): This will execute the request synchronously.
  2. response.body().data.children.map {…}: Here we use the List function “map” to transform every children into a RedditNewsItem.
  3. it.data: “it” is a short way to access a single parameter from the lambda expression. This is only valid when you receive just one parameter, otherwise for more parameters you have to specify it, for example with two parameters it looks like this “x, y -> …”.
  4. subscriber.onError(): We are creating a new Throwable object with the response.message() that we receive from the service.

Commit

https://github.com/juanchosaravia/KedditBySteps/commit/2f90d6dc1369b60ad8ea1382764045dcf730ef76

With this last changes we are now showing the first 10 news from Reddit in our app :)

Conclusion

OK we are getting really close to finish the App! Retrofit is a really awesome library and for sure we are just using a small part of all that you can do with it, probably I’ll be writing more about Retrofit in another Post as it’s really a super powerful library to invoke an API.

In the Next Part we are going to add infinite Scroll to get more news from the Top list.

Thanks!

Twitter: https://twitter.com/juanchosaravia

Next Article

Part 7: Infinite Scroll: Higher-Order functions & Lambdas

--

--