I am working on an Android app that uses Ktor for HTTP requests to an API. Depending upon the query, the response may contain a list of one of two types. The code works when I define four data classes: One each for the response types and two different result data classes -- one for each result type. However, I would like to know if it's possible to use only one response data class and tell it which data class to use for the list when I make the HTTP request.
I'm using the Kotlin serialization library.
The classes look like the following:
@Serializable
data class ResultOne(
val count: Int,
val result: List<TypeOne>
)
@Serializable
data class ResultTwo(
val count: Int,
val result: List<Type2>
)
@Serializable
data class TypeOne(
val str1: String,
val str2: String,
val int1: Int
)
@Serializable
data class TypeTwo(
val str1: String,
val dbl1: Double,
val int1: Int
)
And the request looks something like this:
...
import io.ktor.serialization.kotlinx.json.json
...
private val httpClient = HttpClient {
install(ContentNegotiation) {
json(Json{
isLenient = true
ignoreUnknownKeys = true
})
}
}
fun getResultTypeOne() {
val response = responseOne(listOf(1, 2)).result
}
private suspend fun responseOne(ints: List<Int>): ResultOne {
val availableShows = httpClient.get("https://my.api.com/search")
return availableShows.body()
}
fun getResultTypeTwo() {
val response = responseTwo(listOf(1, 2)).result
}
private suspend fun responseTwo(ints: List<Int>): ResultTwo {
val availableShows = httpClient.get("https://my.api.com/search")
return availableShows.body()
}
There's a bit of redundancy in the HTTP calls, as they are the same with the exception of specifying a different data class for the difference result types. Is there a way to instead reuse the same HTTP call, but tell it which result type to expect in that call?
Of course, it is possible. You should replace your ResultOne
and ResultTwo
classes with one generic class:
@Serializable
data class Result <T> (
val count: Int,
val result: T
)
This way, you can reuse your Result
class for both TypeOne
and TypeTwo
, and your HTTP requests can be simplified:
private val httpClient = HttpClient {
install(ContentNegotiation) {
json(Json{
isLenient = true
ignoreUnknownKeys = true
})
}
}
fun getResultOne(){
val response = response<TypeOne>(listOf(1, 2)).result
}
fun getResultTwo(){
val response = response<TypeTwo>(listOf(1, 2)).result
}
private suspend fun <T> response(ints: List<Int>): Result<T> {
val availableShows = httpClient.get("https://my.api.com/search")
return availableShows.body()
}
If you have other questions, feel free to ask.