Simple steps to consume AWS pre-signed url in Android
Tags: android, aws, retrofit, moshi
Published: 2019-11-30 15:38:34

I have learned very useful information from articles published by several great contributors in the community. This is the first time I am trying to give something back to the community. 
Recently I came across a simple requirement of consuming an AWS pre-signed url in android and displaying the json data in a list, e.g. 

`https://s3-us-east-1.amazonaws.com/something/foo_bar.json`

In the beginning, it felt fairly simple; just another API consumption task. With this thought I started implementing the network, persistence and repository layer first. 

For this example, I am using `Room` for database, `Retrofit` for network communication, `Moshi` for json adapter. The basic requirement is pretty straight forward: when app launches, get the data, store and display in the list. When I started the implementation, I under the impression that consuming this endpoint would be as simple of consuming any other `REST`ful api. But it turned out to be a bit tricky. 
So, below are simple steps to implement this requirement:

*Setting up Retrofit adapter*

``` kotlin 
    object FooRetrofit {

      val conversionFactory: MoshiConverterFactory by lazy {
          MoshiConverterFactory.create()
      }
      
      val retrofit: Retrofit by lazy {
          Retrofit.Builder().apply {
              baseUrl("https://amazonaws.com")
              addConverterFactory(conversionFactory)
          }.build()
      }
   }
```

Notice that I have used a `dummy` url as baseUrl when build the `Retrofit` client. I will explain why I did this later in the article.

*Setting up Repository*
```kotlin
    class FooRepository {
        /* Dao and Service are provided here*/
        
        suspend fun getData(url: String) : List<Data> {
            val dataList = service.getData(url).data
            dao.insertAll()
            return dataList
        }
    }
```
The `repository` class will call the `service` class to fetch data, `insert` to local storage (Room) and return the list.

*Setting up service/ endpoint*
```kotlin
    interface FooService {
        @Get
        suspend fun getData(@Url url: String): FooResponse
    }
```

Now, we see that the `getData()` function in our service is expecting an `url` as argument. Earlier, when we setup the adapter, we set up with the dummy url. The reasoning behind that is, if we setup the adapter with the given url, i.e. `https://s3-useast1.amazonaws.com/something/foo_bar.json` , compiler will throw an exception, `baseUrl should end with '/'`. To overcome this issue, we setup the adapter with a dummy url that meets the requirement.

*Setup calling class/ ViewModel*
```kotlin
    class FooViewModel: ViewModel() {

       /* repository is provided here */

        init {
            launch { 
                fetchData()
            }
        }

        internal suspend fun fetchData() {
            val result = repository.getData(URL)
            // And this result is our json data. The fragment/ activity associated with displaying this data can observe this `LiveData` or `Channel` or `Flow` and when data is received then display.
        }
            
        companion object {
            const val URL = "https://s3-us-east-1.amazonaws.com/something/foo_bar.json"
        }
    }
```

The sample `json` data for this implementation is:
```javascript
    {
      "user": {
      "name": "Foo Bar",
      "address1": "Moon",
      "address2": "Mars"  
      },
      "books": [
      {
       "isbn": "asdf4fjklm02454ac3",
        "author": "Alien 1",
        "category": "Fiction",
        "price": 100
      },
      {
       "isbn": "asdf4f234m02454ac3",
       "author": "Alien 2",
       "category": "Drama",
       "price": 75
     }
     ...
     ]
   }
```
This was the first time I came across this type of requirement. If we had to do `two-way` communication, I believe there would be a different setup. But for simply consuming a pre-signed url, these were the simple steps. 
This is my first article. So, please feel free to provide feedback. I look forward to sharing more with the community in the days to come.

Thank you!