Updated on 2026-08-14
This commit is contained in:
parent
194e750c93
commit
04bcb44f76
6 changed files with 55 additions and 25 deletions
|
|
@ -7,34 +7,51 @@ package com.tangem.datasource.api.common.response
|
|||
*/
|
||||
sealed class ApiResponse<T : Any> {
|
||||
|
||||
/**
|
||||
* Represents a successful response from the API.
|
||||
*
|
||||
* @property data The data returned by the API.
|
||||
*/
|
||||
data class Success<T : Any>(val data: T) : ApiResponse<T>()
|
||||
/** Map of headers (header name with list of values) */
|
||||
abstract val headers: Map<String, List<String>>
|
||||
|
||||
/**
|
||||
* Represents an error response or failure from the API.
|
||||
* Represents a successful response from the API
|
||||
*
|
||||
* @property cause The cause of the error.
|
||||
* @property data the data returned by the API
|
||||
* @property headers the headers returned by the API
|
||||
*/
|
||||
data class Error(val cause: ApiResponseError) : ApiResponse<Nothing>()
|
||||
data class Success<T : Any>(
|
||||
val data: T,
|
||||
override val headers: Map<String, List<String>> = emptyMap(),
|
||||
) : ApiResponse<T>()
|
||||
|
||||
/**
|
||||
* Represents an error response or failure from the API
|
||||
*
|
||||
* @property cause the cause of the error
|
||||
* @property headers the headers returned by the API
|
||||
*/
|
||||
data class Error(
|
||||
val cause: ApiResponseError,
|
||||
override val headers: Map<String, List<String>> = emptyMap(),
|
||||
) : ApiResponse<Nothing>()
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps data in a [ApiResponse.Success] instance.
|
||||
* Wraps data in a [ApiResponse.Success] instance
|
||||
*
|
||||
* @param data The data to wrap.
|
||||
* @return A [ApiResponse.Success] instance containing the provided data.
|
||||
* @param data the data to wrap
|
||||
* @param headers the headers returned by the API
|
||||
* @return a [ApiResponse.Success] instance containing the provided data
|
||||
*/
|
||||
internal fun <T : Any> apiSuccess(data: T): ApiResponse<T> = ApiResponse.Success(data)
|
||||
internal fun <T : Any> apiSuccess(data: T, headers: Map<String, List<String>>): ApiResponse<T> {
|
||||
return ApiResponse.Success(data, headers)
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps an [ApiResponseError] in a [ApiResponse.Error] instance.
|
||||
* Wraps an [ApiResponseError] in a [ApiResponse.Error] instance
|
||||
*
|
||||
* @param cause The error to wrap.
|
||||
* @return A [ApiResponse.Error] instance containing the provided error.
|
||||
* @param cause the error to wrap
|
||||
* @param headers the headers returned by the API
|
||||
* @return a [ApiResponse.Error] instance containing the provided error
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
internal fun <T : Any> apiError(cause: ApiResponseError): ApiResponse<T> = ApiResponse.Error(cause) as ApiResponse<T>
|
||||
internal fun <T : Any> apiError(cause: ApiResponseError, headers: Map<String, List<String>>): ApiResponse<T> {
|
||||
return ApiResponse.Error(cause, headers) as ApiResponse<T>
|
||||
}
|
||||
|
|
@ -47,7 +47,8 @@ internal class ApiResponseCallDelegate<T : Any>(
|
|||
Timber.e(e, "onFailure UnknownException")
|
||||
ApiResponseError.UnknownException(e)
|
||||
}
|
||||
val safeResponse = apiError<T>(error)
|
||||
|
||||
val safeResponse = apiError<T>(cause = error, headers = emptyMap())
|
||||
|
||||
responseCallback.onResponse(this@ApiResponseCallDelegate, Response.success(safeResponse))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ sealed class ApiResponseError : Exception() {
|
|||
|
||||
// region Error Codes
|
||||
enum class Code(val numericCode: Int) {
|
||||
// 3xx Server Errors
|
||||
NOT_MODIFIED(numericCode = 304),
|
||||
// 4xx Server Errors
|
||||
BAD_REQUEST(numericCode = 400),
|
||||
UNAUTHORIZED(numericCode = 401),
|
||||
|
|
@ -64,10 +66,6 @@ sealed class ApiResponseError : Exception() {
|
|||
;
|
||||
|
||||
override fun toString(): String = "$numericCode - $name"
|
||||
|
||||
companion object {
|
||||
val values = values()
|
||||
}
|
||||
}
|
||||
// endregion Error Codes
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,4 +19,14 @@ inline fun <T> catchApiResponseError(onError: (ApiResponseError) -> Unit, block:
|
|||
onError(e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the [ApiResponseError] is a network-related error.
|
||||
* You can provide a custom predicate [codePredicate] to check for specific HTTP status codes.
|
||||
*/
|
||||
inline fun ApiResponseError.isNetworkError(
|
||||
codePredicate: (ApiResponseError.HttpException.Code) -> Boolean = { true },
|
||||
): Boolean {
|
||||
return this is ApiResponseError.HttpException && codePredicate(this.code)
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
package com.tangem.datasource.api.common.response
|
||||
|
||||
const val IF_NONE_MATCH_HEADER = "IfNoneMatch"
|
||||
|
|
@ -12,12 +12,13 @@ import java.util.concurrent.TimeoutException
|
|||
import javax.net.ssl.SSLHandshakeException
|
||||
|
||||
internal fun <T : Any> Response<T>.toSafeApiResponse(analyticsErrorHandler: AnalyticsErrorHandler): ApiResponse<T> {
|
||||
val headers = headers().toMultimap()
|
||||
val body = body()
|
||||
|
||||
return if (isSuccessful && body != null) {
|
||||
apiSuccess(body)
|
||||
apiSuccess(data = body, headers = headers)
|
||||
} else {
|
||||
val code = ApiResponseError.HttpException.Code.values
|
||||
val code = ApiResponseError.HttpException.Code.entries
|
||||
.firstOrNull { it.numericCode == code() }
|
||||
val e = try {
|
||||
if (code == null) {
|
||||
|
|
@ -33,7 +34,7 @@ internal fun <T : Any> Response<T>.toSafeApiResponse(analyticsErrorHandler: Anal
|
|||
ApiResponseError.UnknownException(e)
|
||||
}
|
||||
|
||||
apiError(e)
|
||||
apiError(e, headers)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue