Skip to content

Commit 05e3dff

Browse files
authored
feat: Deprecate ApiResponse.translatedError (#340)
2 parents 685a07d + 14ea13a commit 05e3dff

File tree

4 files changed

+93
-36
lines changed

4 files changed

+93
-36
lines changed

Legacy/src/main/java/com/infomaniak/lib/core/api/ApiController.kt

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* Infomaniak Core - Android
3-
* Copyright (C) 2022-2024 Infomaniak Network SA
3+
* Copyright (C) 2022-2025 Infomaniak Network SA
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU General Public License as published by
@@ -17,21 +17,20 @@
1717
*/
1818
package com.infomaniak.lib.core.api
1919

20-
import androidx.annotation.StringRes
2120
import com.google.gson.Gson
2221
import com.google.gson.GsonBuilder
2322
import com.google.gson.JsonParser
2423
import com.google.gson.reflect.TypeToken
2524
import com.infomaniak.lib.core.BuildConfig.LOGIN_ENDPOINT_URL
2625
import com.infomaniak.lib.core.InfomaniakCore
27-
import com.infomaniak.lib.core.R
2826
import com.infomaniak.lib.core.auth.TokenInterceptorListener
2927
import com.infomaniak.lib.core.models.ApiError
3028
import com.infomaniak.lib.core.models.ApiResponse
3129
import com.infomaniak.lib.core.models.ApiResponseStatus.ERROR
3230
import com.infomaniak.lib.core.networking.HttpClient
3331
import com.infomaniak.lib.core.networking.HttpUtils
3432
import com.infomaniak.lib.core.utils.CustomDateTypeAdapter
33+
import com.infomaniak.lib.core.utils.ErrorCodeTranslated
3534
import com.infomaniak.lib.core.utils.isNetworkException
3635
import com.infomaniak.lib.core.utils.isSerializationException
3736
import com.infomaniak.lib.login.ApiToken
@@ -191,8 +190,8 @@ object ApiController {
191190
scope.setExtra("bodyResponse", bodyResponse)
192191
}
193192
createErrorResponse(
194-
apiError = createApiError(useKotlinxSerialization, bodyResponse, ServerErrorException(bodyResponse)),
195-
translatedError = R.string.serverError,
193+
InternalTranslatedErrorCode.UnknownError,
194+
InternalErrorPayload(ServerErrorException(bodyResponse), useKotlinxSerialization, bodyResponse),
196195
buildErrorResult = buildErrorResult,
197196
)
198197
}
@@ -202,7 +201,7 @@ object ApiController {
202201
}
203202
} catch (refreshTokenException: RefreshTokenException) {
204203
refreshTokenException.printStackTrace()
205-
return createErrorResponse(translatedError = R.string.anErrorHasOccurred, buildErrorResult = buildErrorResult)
204+
return createErrorResponse(InternalTranslatedErrorCode.UnknownError, buildErrorResult = buildErrorResult)
206205
} catch (exception: Exception) {
207206
exception.printStackTrace()
208207

@@ -217,8 +216,8 @@ object ApiController {
217216
}
218217

219218
createErrorResponse(
220-
translatedError = R.string.anErrorHasOccurred,
221-
apiError = createApiError(useKotlinxSerialization, bodyResponse, exception = exception),
219+
InternalTranslatedErrorCode.UnknownError,
220+
InternalErrorPayload(exception, useKotlinxSerialization, bodyResponse),
222221
buildErrorResult = buildErrorResult,
223222
)
224223
}
@@ -232,7 +231,9 @@ object ApiController {
232231
}
233232

234233
if (apiResponse is ApiResponse<*> && apiResponse.result == ERROR) {
235-
apiResponse.translatedError = R.string.anErrorHasOccurred
234+
@Suppress("DEPRECATION")
235+
apiResponse.translatedError = InternalTranslatedErrorCode.UnknownError.translateRes
236+
apiResponse.error = InternalTranslatedErrorCode.UnknownError.toApiError()
236237
}
237238

238239
return apiResponse
@@ -245,26 +246,20 @@ object ApiController {
245246
inline fun <reified T> createInternetErrorResponse(
246247
noNetwork: Boolean = false,
247248
noinline buildErrorResult: ((apiError: ApiError?, translatedErrorRes: Int) -> T)?,
248-
) = createErrorResponse<T>(
249-
translatedError = if (noNetwork) R.string.noConnection else R.string.connectionError,
250-
apiError = ApiError(exception = NetworkException()),
249+
): T = createErrorResponse<T>(
250+
if (noNetwork) InternalTranslatedErrorCode.NoConnection else InternalTranslatedErrorCode.ConnectionError,
251+
InternalErrorPayload(NetworkException()),
251252
buildErrorResult = buildErrorResult,
252253
)
253254

254-
fun createApiError(useKotlinxSerialization: Boolean, bodyResponse: String, exception: Exception) = ApiError(
255-
contextJson = if (useKotlinxSerialization) bodyResponse.bodyResponseToJson() else null,
256-
contextGson = when {
257-
useKotlinxSerialization -> null
258-
else -> runCatching { JsonParser.parseString(bodyResponse).asJsonObject }.getOrDefault(null)
259-
},
260-
exception = exception
261-
)
262-
263255
inline fun <reified T> createErrorResponse(
264-
@StringRes translatedError: Int,
265-
apiError: ApiError? = null,
256+
internalErrorCode: InternalTranslatedErrorCode,
257+
payload: InternalErrorPayload? = null,
266258
noinline buildErrorResult: ((apiError: ApiError?, translatedErrorRes: Int) -> T)?,
267259
): T {
260+
val apiError = createDetailedApiError(internalErrorCode, payload)
261+
val translatedError = internalErrorCode.translateRes
262+
268263
return buildErrorResult?.invoke(apiError, translatedError)
269264
?: ApiResponse<Any>(result = ERROR, error = apiError, translatedError = translatedError) as T
270265
}
@@ -275,4 +270,27 @@ object ApiController {
275270
enum class ApiMethod {
276271
GET, PUT, POST, DELETE, PATCH
277272
}
273+
274+
data class InternalErrorPayload(
275+
val exception: Exception? = null,
276+
val useKotlinxSerialization: Boolean? = null,
277+
val bodyResponse: String? = null,
278+
)
279+
280+
fun ErrorCodeTranslated.toApiError(): ApiError = createDetailedApiError(this, null)
281+
282+
fun createDetailedApiError(errorCode: ErrorCodeTranslated, payload: InternalErrorPayload? = null): ApiError {
283+
val useKotlinxSerialization = payload?.useKotlinxSerialization
284+
return ApiError(
285+
code = errorCode.code,
286+
contextJson = if (useKotlinxSerialization == true) payload.bodyResponse?.bodyResponseToJson() else null,
287+
contextGson = when {
288+
useKotlinxSerialization == true -> null
289+
else -> errorCode.runCatching {
290+
payload?.let { JsonParser.parseString(it.bodyResponse).asJsonObject }
291+
}.getOrDefault(null)
292+
},
293+
exception = payload?.exception
294+
)
295+
}
278296
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Infomaniak Core - Android
3+
* Copyright (C) 2025 Infomaniak Network SA
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
package com.infomaniak.lib.core.api
19+
20+
import androidx.annotation.StringRes
21+
import com.infomaniak.lib.core.R
22+
import com.infomaniak.lib.core.utils.ErrorCodeTranslated
23+
24+
enum class InternalTranslatedErrorCode(
25+
override val code: String,
26+
@StringRes override val translateRes: Int,
27+
) : ErrorCodeTranslated {
28+
NoConnection("no_connection", R.string.noConnection),
29+
ConnectionError("connection_error", R.string.connectionError),
30+
UnknownError("an_error_has_occurred", R.string.anErrorHasOccurred),
31+
UserAlreadyPresent("user_already_present", R.string.errorUserAlreadyPresent),
32+
}

Legacy/src/main/java/com/infomaniak/lib/core/models/ApiResponse.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* Infomaniak Core - Android
3-
* Copyright (C) 2022-2024 Infomaniak Network SA
3+
* Copyright (C) 2022-2025 Infomaniak Network SA
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU General Public License as published by
@@ -27,13 +27,18 @@ open class ApiResponse<T>(
2727
val result: ApiResponseStatus = ApiResponseStatus.UNKNOWN,
2828
val data: @RawValue T? = null,
2929
val uri: String? = null,
30-
val error: ApiError? = null,
30+
var error: ApiError? = null,
3131
val page: Int = 0,
3232
val pages: Int = 0,
3333
@SerialName("response_at")
3434
@SerializedName("response_at")
3535
val responseAt: Long = 0,
3636
val total: Int = 0,
37+
@Deprecated(
38+
"translatedError doesn't take into account project specific translated errors specified through " +
39+
"InfomaniakCore.apiErrorCodes. Use translateError() instead",
40+
ReplaceWith("translateError()", "com.infomaniak.lib.core.utils.ApiErrorCode.Companion.translateError"),
41+
)
3742
var translatedError: Int = 0,
3843
@SerialName("items_per_page")
3944
@SerializedName("items_per_page")

Legacy/src/main/java/com/infomaniak/lib/core/utils/ApiErrorCode.kt

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* Infomaniak Core - Android
3-
* Copyright (C) 2023-2024 Infomaniak Network SA
3+
* Copyright (C) 2023-2025 Infomaniak Network SA
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU General Public License as published by
@@ -19,26 +19,28 @@ package com.infomaniak.lib.core.utils
1919

2020
import androidx.annotation.StringRes
2121
import com.infomaniak.lib.core.InfomaniakCore
22-
import com.infomaniak.lib.core.R
22+
import com.infomaniak.lib.core.api.InternalTranslatedErrorCode
2323
import com.infomaniak.lib.core.models.ApiResponse
2424

25-
data class ApiErrorCode(val code: String, @StringRes val translateRes: Int) {
25+
interface ErrorCodeTranslated {
26+
val code: String
27+
@get:StringRes
28+
val translateRes: Int
29+
}
2630

31+
data class ApiErrorCode(override val code: String, @StringRes override val translateRes: Int) : ErrorCodeTranslated {
2732
companion object {
28-
29-
const val AN_ERROR_HAS_OCCURRED = "an_error_has_occured"
30-
31-
private val defaultApiErrorCode = ApiErrorCode(AN_ERROR_HAS_OCCURRED, R.string.anErrorHasOccurred)
32-
3333
@StringRes
3434
fun <T> ApiResponse<T>.translateError(): Int = formatError().translateRes
3535

36-
fun <T> ApiResponse<T>.formatError(): ApiErrorCode {
36+
fun <T> ApiResponse<T>.formatError(): ErrorCodeTranslated {
3737
val errorCode = error?.code
3838
return if (errorCode == null) {
39-
defaultApiErrorCode
39+
InternalTranslatedErrorCode.UnknownError
4040
} else {
41-
InfomaniakCore.apiErrorCodes?.firstOrNull { it.code.equals(errorCode, ignoreCase = true) } ?: defaultApiErrorCode
41+
InfomaniakCore.apiErrorCodes?.firstOrNull { it.code.equals(errorCode, ignoreCase = true) }
42+
?: InternalTranslatedErrorCode.entries.firstOrNull { it.code.equals(errorCode, ignoreCase = true) }
43+
?: InternalTranslatedErrorCode.UnknownError
4244
}
4345
}
4446
}

0 commit comments

Comments
 (0)