Ktorfit
Ktorfit copied to clipboard
Throw a HttpException when the request is sucessfull but the http status are not 2XX, like Retrofit
Is your feature request related to a problem? Please describe.
Using Retrofit, by default, when using suspend, when an API returns successfully (the backend actual responds), when the status code is not success (2XX) it throws a custom HttpException
.
When working with Ktorfit and Ktor, when using Suspend and the direct type of the Response Body, when the server returns a 4XX with a Custom Body or Any Body at all, the Exception is ContentConvertException
, this does not say nothing of what was the really cause of the error.
Describe the solution you'd like Creating a custom HttpException and throwing the Exception when the response is not 2XX like Retrofit does: https://github.com/square/retrofit/blob/8abb8af6ce730b137c2a9f95c3bb5164c93e955e/retrofit-adapters/scala/src/main/java/retrofit2/adapter/scala/BodyCallAdapter.java#L47-L51
Describe alternatives you've considered
There are workarounds that I found that is not the best but is working so far for me that is creating a custom Converter.SuspendResponseConverter<HttpResponse, Any>
that overrides the default IMPL of Ktorfit.
ktorfit {
....
converterFactories(UnsuccessResponseConverterFactory())
}
public class KtorfitHttpException(
@Transient public val response: HttpResponse,
public val bodyText: String,
) : RuntimeException() {
override val message: String
get() = "HTTP " + response.status.value + " " + bodyText
}
internal class UnsuccessResponseConverterFactory : Converter.Factory {
class UnsuccessResponseSuspendConverter(
val typeData: TypeData,
val ktorfit: Ktorfit
) : Converter.SuspendResponseConverter<HttpResponse, Any> {
override suspend fun convert(response: HttpResponse): Any {
return try {
if (response.status.isSuccess()) {
response.call.body(typeData.typeInfo)
} else {
throw KtorfitHttpException(response, response.bodyAsText())
}
} catch (exception: Exception) {
throw exception
}
}
}
override fun suspendResponseConverter(
typeData: TypeData,
ktorfit: Ktorfit
): Converter.SuspendResponseConverter<HttpResponse, *>? {
if (typeData.typeInfo.type != Response::class) {
return UnsuccessResponseSuspendConverter(typeData, ktorfit)
}
return null
}
}