I'm new in Kotlin as a PHP dev. I have a data model, something like this:
@Serializable
data class Site (
@SerialName("id")
val id: Int,
@SerialName("name")
val name: String,
@SerialName("accountId")
val accountId: Int,
}
I have JSON output something like the following, which comes from a external API and which I am unable to control:
{
"sites": {
"count": 1,
"site": [
{
"id": 12345,
"name": "Foobar",
"accountId": 123456
}
]
}
}
When trying to get this from the API with ktor HTTPClient, I'd like to instruct the serializer to use sites.site
as the root for my Site
datamodel. Currently, I get the error: Uncaught Kotlin exception: io.ktor.serialization.JsonConvertException: Illegal input
and Caused by: kotlinx.serialization.json.internal.JsonDecodingException: Expected start of the array '[', but had 'EOF' instead at path: $
I'm using the following to fetch the endpoint:
package com.example.myapplication.myapp
import com.example.myapplication.myapp.models.Site
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.*
import io.ktor.serialization.kotlinx.json.*
import kotlinx.serialization.json.Json
class Api {
private val client = HttpClient {
install(ContentNegotiation) {
json(Json {
prettyPrint = true
isLenient = true
ignoreUnknownKeys = true
})
}
}
private val apiKey = "REDACTED"
private val installationId = "REDACTED"
private val apiHost = "REDACTED"
suspend fun getSitesList(): List<Site> {
return get("sites/list").body()
}
suspend fun get(endpoint: String): HttpResponse {
val response = client.get(buildEndpointUrl(endpoint))
return response
}
private fun buildEndpointUrl(endpoint: String): HttpRequestBuilder {
val builder = HttpRequestBuilder()
val parametersBuilder = ParametersBuilder()
parametersBuilder.append("api_key", apiKey)
builder.url {
protocol = URLProtocol.HTTPS
host = apiHost
encodedPath = endpoint
encodedParameters = parametersBuilder
}
builder.header("Accept", "application/json")
return builder
}
}
You have to model the whole response object and cannot just provide a model for some of its parts.
@Serializable
data class SitesResponse(
val sites: SitesContainer,
)
@Serializable
data class SitesContainer(
val count: Int,
val site: List<Site>,
)
@Serializable
data class Site(
val accountId: Int,
val id: Int,
val name: String,
)