I am looking for a better way to handle errors and exceptions.
I want to catch the exception and pass it back to the caller of this function. But the method signature is <LoginResponseDto, ErrorResponseDto>
The ErrorResponseDto is the model I will get back when the API return a status code error. However, its possible a exception could be thrown and I would like to bubble that up to the caller as well.
I am not sure its possible with my current implementation.
What is the best way to handle something like this
override suspend fun loginUser(loginRequestModel: LoginRequestModel): APIResponse<LoginResponseDto, ErrorResponseDto> {
return try {
val response = httpClient
.post("https://endpoint") {
contentType(ContentType.Application.Json)
setBody(
LoginRequestDto(
/* body data */
)
)
}
if (response.status.value == 200) {
APIResponse.OnSuccess(response.body())
}
else {
APIResponse.OnFailure(response.body())
}
}
catch (exception: Exception) {
if (exception is CancellationException) {
Timber.e(exception)
throw exception
}
else {
Timber.e(exception)
// This works as I am still return the ErrorResponseDto
APIResponse.OnFailure(ErrorResponseDto(
errors = listOf(
ErrorDto(
code = exception.localizedMessage ?: "",
detail = exception.message ?: "Unknown"))))
// But what I would want to do is this
APIResponse.OnFailure(exception)
}
}
}
interface APIResponse<out T, out E> {
data class OnSuccess<T>(val data: T) : APIResponse<T, Nothing>
data class OnFailure<E>(val error: E) : APIResponse<Nothing, E>
}
data class ErrorResponseDto(
val errors: List<ErrorDto>
)
data class ErrorDto(
val code: String,
val detail: String
)