I have written a common code in a common module as below and tested in JS environment
val response = client.post<HttpResponse>(url) {
body = TextContent("""{"a":1,"b":2}""", ContentType.Application.Json)
}
if (response.status != HttpStatusCode.OK) {
logger.error("Error, this one failed bad?")
}
But my code ends at client.post with a canceled corutineException on no network. How do I handle this and any other exception? If there is an internet connection. Nothing fails, I want to be able to handle the exceptions. How?
Note: try, catch doesn't work
We can handle it in a central way using this extension function that wraps Success and error cases. We can have Network Error, Serialisation Error or Server Errors which may expose error bodies/messages for the UI and http status code.
suspend inline fun <reified T, reified E> HttpClient.safeRequest(
block: HttpRequestBuilder.() -> Unit,
): ApiResponse<T, E> =
try {
val response = request { block() }
ApiResponse.Success(response.body())
} catch (e: ClientRequestException) {
ApiResponse.Error.HttpError(e.response.status.value, e.errorBody())
} catch (e: ServerResponseException) {
ApiResponse.Error.HttpError(e.response.status.value, e.errorBody())
} catch (e: IOException) {
ApiResponse.Error.NetworkError
} catch (e: SerializationException) {
ApiResponse.Error.SerializationError
}
suspend inline fun <reified E> ResponseException.errorBody(): E? =
try {
response.body()
} catch (e: SerializationException) {
null
}
Here's the ApiResponse
defined below so there's working code:
sealed class ApiResponse<out T, out E> {
/**
* Represents successful network responses (2xx).
*/
data class Success<T>(val body: T) : ApiResponse<T, Nothing>()
sealed class Error<E> : ApiResponse<Nothing, E>() {
/**
* Represents server (50x) and client (40x) errors.
*/
data class HttpError<E>(val code: Int, val errorBody: E?) : Error<E>()
/**
* Represent IOExceptions and connectivity issues.
*/
object NetworkError : Error<Nothing>()
/**
* Represent SerializationExceptions.
*/
object SerializationError : Error<Nothing>()
}
}
I found ApiResponse
works well for my case but you don't necessarily have to model your api responses as this if you have other/special cases, you can also use kotlin-result or Arrow's Either.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With