Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parsing an error body in a ktor HTTPClient

I have an api that returns error body with the correct error information when a bad request is sent. For eg I get status code 400 and the following body -

{
  "errorCode": 1011,
  "errorMessage": "Unable to get Child information"
}

Now when I am writing a ktor client in a multi-platform module for this, I catch this in a response validator like -

 HttpResponseValidator {
            validateResponse {
                val statusCode = it.status.value
                when (statusCode) {
                    in 300..399 -> print(it.content.toString())
                    in 400..499 -> {
                        print(it.content.toString())
                        throw ClientRequestException(it)
                    }
                    in 500..599 -> print(it.content.toString())
                }
            }
            handleResponseException {
                print(it.message)
            }
        }

My query here is I am not able to access the response error body in either validateResponse or handleResponseException. Is there a way i can catch and parse that to get the actual error sent by server?

like image 652
Kapil G Avatar asked Dec 30 '22 23:12

Kapil G


1 Answers

You can declare a data class Error to represent the error response you expect.

import kotlinx.serialization.Serializable

@Serializable
data class Error(
    val errorCode: Int,   //if by errorCode you mean the http status code is not really necessary to include here as you already know it from the validateResponse
    val errorMessage: String
)

you can have a suspend fun to parse the response and have it as an instance of the Error data class

 suspend fun getError(responseContent: ByteReadChannel): Error {
    responseContent.readUTF8Line()?.let {
        return Json(JsonConfiguration.Stable).parse(Error.serializer(), it)
    }
    throw IllegalArgumentException("not a parsable error")
}

then inside the handleResponseException

handleResponseException { cause -> 
            val error = when (cause) {
                is ClientRequestException -> exceptionHandler.getError(cause.response.content)
// other cases here 

                else -> // throw Exception() do whatever you need 
            }
//resume with the error 
        }

you can implement some logic based on the error you get to throw an exception and catch it somewhere else in your code for example

when (error.errorCode) {
        1-> throw MyCustomException(error.errorMessage)
        else -> throw Exception(error.errorMessage)
    }

I hope it helps

like image 110
dimitris boutas Avatar answered Jan 04 '23 16:01

dimitris boutas