I Just started to explore KMM, which seems really nice so far.
Basically, what I'm trying to to is to handle all http error code (like 401, 404, 500) globally, in one place.
However, I'm not sure how to interact with the response.
I installed ResponseObserver in HttpClient, but it only goes there if http status is 200.
I also tried to use HttpResponseValidator, but it never goes there.
Here's the code:
class ApiImpl : Api {
private val httpClient = HttpClient {
install(JsonFeature) {
val json = kotlinx.serialization.json.Json { ignoreUnknownKeys = true }
serializer = KotlinxSerializer(json)
}
install(ResponseObserver) {
onResponse { response ->
//*** We get here only if http status code is 200 ***/
println("HTTP status: ${response.status.value}")
}
}
HttpResponseValidator {
validateResponse { response: HttpResponse ->
val statusCode = response.status.value
//*** We never get here ***/
println("HTTP status: $statusCode")
when (statusCode) {
in 300..399 -> throw RedirectResponseException(response)
in 400..499 -> throw ClientRequestException(response)
in 500..599 -> throw ServerResponseException(response)
}
if (statusCode >= 600) {
throw ResponseException(response)
}
}
handleResponseException { cause: Throwable ->
throw cause
}
}
}
override suspend fun getUsers(): List<User> {
try {
return httpClient.get("some url....")
} catch (e: Exception) {
//*** We get here in case of 404 (for example), but I don't want to repeat it in every request ***/
println(e.message)
}
return emptyList()
}
}
I've tested your scenario with this sample class (got and modified from official ktor github rep) and I can hit all breakpoints where you'd like to get error codes (e.g. 500
)
package com.example.kmmtest001.shared
import io.ktor.client.*
import io.ktor.client.features.*
import io.ktor.client.features.json.*
import io.ktor.client.features.json.serializer.*
import io.ktor.client.features.observer.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.*
import kotlinx.coroutines.*
internal expect val ApplicationDispatcher: CoroutineDispatcher
class ApplicationApi {
private val client = HttpClient {
install(JsonFeature) {
val json = kotlinx.serialization.json.Json { ignoreUnknownKeys = true }
serializer = KotlinxSerializer(json)
}
install(ResponseObserver) {
onResponse { response ->
println("HTTP status: ${response.status.value}")
}
}
HttpResponseValidator {
validateResponse { response: HttpResponse ->
val statusCode = response.status.value
println("HTTP status: $statusCode")
when (statusCode) {
in 300..399 -> throw RedirectResponseException(response)
in 400..499 -> throw ClientRequestException(response)
in 500..599 -> throw ServerResponseException(response)
}
if (statusCode >= 600) {
throw ResponseException(response)
}
}
handleResponseException { cause: Throwable ->
throw cause
}
}
}
var address = Url("https://tools.ietf.org/rfc/rfc1866.txt")
fun about(callback: (String) -> Unit) {
GlobalScope.apply {
launch(ApplicationDispatcher) {
val result: String = client.get {
url(this@ApplicationApi.address.toString())
}
callback(result)
}
}
}
fun get500ServerError(callback: (String) -> Unit) {
GlobalScope.apply {
launch(ApplicationDispatcher) {
try {
val result: String = client.get {
url("https://www.versionestabile.it/_sw/so/63812313/index500.php")
}
callback(result)
} catch (se: ServerResponseException) {
val statusCode = se.response?.status?.value
callback("HTTP status code: $statusCode --> ${se.message}")
} catch (ce: ClientRequestException) {
val statusCode = ce.response?.status?.value
callback("HTTP status code: $statusCode --> ${ce.message}")
}
}
}
}
}
I've also tested 401
and 404
errors.