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
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
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
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
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:
{
"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!
Top comments (0)