我正在寻找更好的方法来处理错误和异常。
我想捕获异常并将其传递回该函数的调用者。但方法签名是
<LoginResponseDto, ErrorResponseDto>
ErrorResponseDto 是当 API 返回状态代码错误时我将返回的模型。但是,可能会引发异常,我也想将其冒泡给调用者。
我不确定我当前的实现是否可行。
处理此类事情的最佳方法是什么
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 but looks hacky doing it like this
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
)
我个人将客户端设置为期望成功,然后使用封装所有错误的
kotlin.Result
而不是返回奇怪的类型接口。
唯一要记住的是,当 http 调用本身是失败的原因时,Ktor 会给我们
ResponseException
。
override suspend fun loginUser(loginRequestModel: LoginRequestModel): Result<LoginResponseDto> =
runCatching {
// note that client is set up to expect failure so it will throw when response code is not 200
httpClient
.post("https://endpoint") {
contentType(ContentType.Application.Json)
setBody(
LoginRequestDto(
/* body data */
)
)
}.body()
}.onFailure {
// bubble up cancellation
if (it is CancellationException) throw it
}
现在在呼叫站点中剩下的就是:
api.loginUser(loginModel).fold (
onSuccess = { loginDto -> handleSuccessfullLogin(loginDto) },
onFailure = { error ->
when (error) {
is ResponseException -> { // http call failed here
error.response.status // returned code and message is here
}
else -> { // other causes }
}
}
)
ResponseException
如何包含完整的HttpResonse
,这意味着如果需要的话我们也可以尝试获取错误.body()
。