Work flow for dealing with Retrofit in Android
Tags: kotlin, mobile, android, tristan
Published: 2023-07-17 15:58:49

### Table of contents
1. [Read First](#first)
2. [My workflow](#work)
3. [Use Postman to query endpoint](#post)
4. [Model response object](#model)
5. [Create method in interface](#create)
6. [Create method in Repository](#repo)

### The code
- [GitHub](https://github.com/thePlebDev/Clicker)

### YouTube version
- [YouTube](https://youtu.be/nUiHXrcSv0o)

### Introduction <a name="intro"></a>
- I have embarked on my next app, a Twitch client app. This series will be all my notes and problems faced when creating this app.

### READ FIRST <a name="first"></a>
- This tutorial already assumes you are familiar with [Retrofit](https://square.github.io/retrofit/) and have retrofit up and running in your app. This tutorial is meant to be a more abstract guide and give individuals a broad understanding of my work flow. Don't focus too much on the details, it is the series of steps within this workflow that are most helpful


### Workflow when using Retrofit <a name="work"></a>
- As I have been working with the [Twitch API](https://dev.twitch.tv/docs/api/reference/), I have been dealing a lot with Retrofit. So much so that I have developed a little workflow for when I need to call a new endpoint of the API. The workflow consists of 4 steps:

**1) Use [Postman](https://www.postman.com/) to query endpoint**
**2) Model the response object**
**3) Create method in Retrofit interface**
**4) Create method in the Repository layer**


### 1) Use Postman to query the endpoint <a name="post"></a>
- Documentation can only tell us so much and sometimes it can be out of date or incorrect. That is why before I start coding I like to query the endpoint with [Postman](https://www.postman.com/).  This has two main benefits: 

**1)** Verifies that we are hitting the proper endpoint with all the proper headers and parameters. 

**2)** Gives us a proper example of what the response object will be. It is also important that we verify that the response object is in JSON. JSON is the proper format that Retrofit will use to convert to our Kotlin object

### 2) Model the response object <a name="model"></a>
- So lets assume we are using the [get-streams](https://dev.twitch.tv/docs/api/reference/#get-followed-streams) API endpoint. Upon a successful response, we will get a JSON object that looks something like this:
```
"data": [
        {
            "id": "40457151671",
            "user_id": "582765062",
            "user_login": "premiertwo",
            "user_name": "PremierTwo",
            "game_id": "33214",
            "game_name": "Fortnite",
            "type": "live",
            "title": "fork knife @rubberross @ironmouse @aicandii | Tokyo, Japan | !discord",
            "viewer_count": 3506,
            "started_at": "2023-07-17T08:14:13Z",
            "language": "en",
            "thumbnail_url": "https://static-cdn.jtvnw.net/previews-ttv/live_user_premiertwo-{width}x{height}.jpg",
            "tag_ids": [],
            "tags": [
                "Improv",
                "Forehead",
                "AMA",
                "VoiceActing",
                "Japan",
                "Travel",
                "English",
                "NoSpoilers"
            ],
            "is_mature": false
        },
]


```
- Our modeled response object will then look like this:
```
data class FollowedLiveStreams(
    val data:List<StreamData>
)

```
```
data class StreamData(
    val id:String,
    @SerializedName("user_id")
    val userId:String,
    @SerializedName("user_login")
    val userLogin:String,
    @SerializedName("user_name")
    val userName:String,
    @SerializedName("game_id")
    val gameId:String,
    @SerializedName("game_name")
    val gameName:String,
    val type:String,
    val title:String,
    @SerializedName("viewer_count")
    val viewerCount:Int,
    @SerializedName("started_at")
    val startedAt:String,
    val language:String,
    @SerializedName("thumbnail_url")
    val thumbNailUrl:String,
    @SerializedName("tag_ids")
    val tagIds:List<String>,
    val tags:List<String>,
    @SerializedName("is_mature")
    val isMature:Boolean

)
```
- There are 2 things you should look out for when trying to model a JSON response object:

**1) [] square brackets :** indicate a list. That is why the Kotlin data class version of `"tags": ["Improv"]` is `val tags:List<String>`

**2) {} curly brackets :** indicates a new object. Which is why we are modeling the JSON response object as two classes. Notice how its `"data": [ {`, the square brackets followed by the curly brackets are telling us that `data` is a list of objects. Which results in our `data:List<StreamData>` value


### 3) Create method in Retrofit interface <a name="create"></a>
- Now is the part where we modify the interface which will represent out Http call. Assuming we are still using the [get-streams](https://dev.twitch.tv/docs/api/reference/#get-streams) API, the call would look like this:
```
import retrofit2.Response
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.Query

@GET("streams/followed")
    suspend fun getFollowedStreams(
        @Header("Authorization") authorization:String,
        @Header("Client-Id") clientId:String,
        @Query("user_id") userId:String
    ): Response<FollowedLiveStreams>

```
- Notice how we can use `@Header `, `@Query ` to define dynamic values for the query parameter and the header. Also, look how the return object is `Response<FollowedLiveStreams>`, we are using the `FollowedLiveStreams` we have created previously. Retrofit will automatically map the JSON object to our `FollowedLiveStreams` object


### 4) Create method in the Repository layer <a name="repo"></a>
- Now inside of the repository layer we can make the actual call the the api, like so:
```
class TwitchRepoImpl(
    private val twitchClient: TwitchClient = TwitchRetrofitInstance.api
) {
suspend fun getFollowedLiveStreams(
        authorizationToken: String,
        clientId: String,
        userId: String
    ): Flow<Response<FollowedLiveStreams>> = flow{
        emit(Response.Loading)
        val response = twitchClient.getFollowedStreams(
            authorization = authorizationToken,
            clientId = clientId,
            userId = userId
        )
        if (response.isSuccessful){
           emit(response.body())
        }else{
          emit(Response.Failure(Exception("Error!, code {${response.code()}}")))

        }
    }

}

```
- The code above might seem a little confusing but to clarify things, the Response object is of my own creation:
```
sealed class Response<out T> {


    object Loading: Response<Nothing>()


    data class Success<out T>(
        val data:T
    ):Response<T>()


    data class Failure(
        val e:Exception
    ):Response<Nothing>()

}
```
- I am returning [Kotlin Flows](https://developer.android.com/kotlin/flow) from `getFollowedLiveStreams()` so my downstream classes (ViewModels) are able to call `collect{}` on this method and react differently depending if the Response is Loading, Success or Failure

- After we have defined the method inside of the repository layer, we are free to use the method as we see fit.


### Conclusion
- Thank you for taking the time out of your day to read this blog post of mine. If you have any questions or concerns please comment below or reach out to me on [Twitter](https://twitter.com/AndroidTristan).