diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponse.kt index 0348dba0e3..b85ea4e10e 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponse.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponse.kt @@ -7,34 +7,51 @@ package com.tangem.datasource.api.common.response */ sealed class ApiResponse { - /** - * Represents a successful response from the API. - * - * @property data The data returned by the API. - */ - data class Success(val data: T) : ApiResponse() + /** Map of headers (header name with list of values) */ + abstract val headers: Map> /** - * 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() + data class Success( + val data: T, + override val headers: Map> = emptyMap(), + ) : ApiResponse() + + /** + * 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> = emptyMap(), + ) : ApiResponse() } /** - * 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 apiSuccess(data: T): ApiResponse = ApiResponse.Success(data) +internal fun apiSuccess(data: T, headers: Map>): ApiResponse { + 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 apiError(cause: ApiResponseError): ApiResponse = ApiResponse.Error(cause) as ApiResponse \ No newline at end of file +internal fun apiError(cause: ApiResponseError, headers: Map>): ApiResponse { + return ApiResponse.Error(cause, headers) as ApiResponse +} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseCallDelegate.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseCallDelegate.kt index 50ee235c7b..28c7fa4f72 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseCallDelegate.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseCallDelegate.kt @@ -47,7 +47,8 @@ internal class ApiResponseCallDelegate( Timber.e(e, "onFailure UnknownException") ApiResponseError.UnknownException(e) } - val safeResponse = apiError(error) + + val safeResponse = apiError(cause = error, headers = emptyMap()) responseCallback.onResponse(this@ApiResponseCallDelegate, Response.success(safeResponse)) } diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseError.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseError.kt index 10ec8add5d..f63826874b 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseError.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseError.kt @@ -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 } diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseExt.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseExt.kt index 0caae8ba1a..41a9f6bc8f 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseExt.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseExt.kt @@ -19,4 +19,14 @@ inline fun 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) } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseHeaders.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseHeaders.kt new file mode 100644 index 0000000000..52464501c9 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ApiResponseHeaders.kt @@ -0,0 +1,3 @@ +package com.tangem.datasource.api.common.response + +const val IF_NONE_MATCH_HEADER = "IfNoneMatch" \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ResponseExt.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ResponseExt.kt index 926d9213aa..a8272de6f1 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ResponseExt.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/response/ResponseExt.kt @@ -12,12 +12,13 @@ import java.util.concurrent.TimeoutException import javax.net.ssl.SSLHandshakeException internal fun Response.toSafeApiResponse(analyticsErrorHandler: AnalyticsErrorHandler): ApiResponse { + 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 Response.toSafeApiResponse(analyticsErrorHandler: Anal ApiResponseError.UnknownException(e) } - apiError(e) + apiError(e, headers) } }