Как обрабатывать как успешные, так и неудачные ответы в Retrofit и RxJava2? - PullRequest
0 голосов
/ 16 ноября 2018

У меня есть следующий запрос:

@POST("devices/link/")
    fun linkDevice(
        @Body deviceInfo: DeviceInfo
    ): Single<Response<UserDevice>>

Я хочу добиться следующего:

  1. Если запрос был успешным, получить DeviceInfo и, в зависимости от кода состояния, сообщить о событии аналитикам

  2. Если запрос не удался, получите исключение, преобразуйте его и перебросьте.

Итак, код:

fun linkDevice(): Single<UserDevice> {
    val deviceInfo = deviceUtil.getDeviceInfo()

    return devicesService
        .linkDevice(deviceInfo)
        .onErrorResumeNext { e ->
            val transformedException = transformRequestException(e) { httpException ->
                return@transformRequestException when (httpException.code()) {
                    409 -> DeviceAlreadyLinkedException()
                    else -> null
                }
            }
            Single.error(transformedException)
        }
        .flatMap { response ->
            if (response.isSuccessful) {
                val userDevice = response.body()

                userDevice?.let {
                    userPreferences.setDeviceId(it.id)
                }

                when (response.code()) {
                    200 -> {
                        // TODO: Analytics
                    }
                    201 -> {
                        // TODO: Analytics
                    }
                }

                Single.just(userDevice)
            } else {
                throw ApiException()
            }
        }
}

/**
 * Transform exception that came from request
 * By default, handles only network and HTTP 401 exceptions, but can contain custom logic, passed with specialTransformer
 */
fun transformRequestException(
    e: Throwable,
    specialTransformer: ((httpException: HttpException) -> Exception?)? = null
): Exception {
    return if (e is HttpException) {
        if (e.code() == 401) {
            NotAuthenticatedException()
        } else {
            specialTransformer?.invoke(e) ?: ApiException()
        }
    } else {
        NetworkException()
    }
}

Но этот код не работает, если я работаю с объектом Response, он будет работать только с Single<UserDevice> в моем сервисе Retrofit.

Но с Single<UserDevice> я не могу получить коды 2XX.

Итак, как реализовать желаемое поведение?

1 Ответ

0 голосов
/ 18 ноября 2018

Итак, на данный момент я решил следующее:

data class RequestResult<T>(
    val data: T,
    val code: Int
)

fun <T> transformResponse(response: Response<T>): Single<RequestResult<T>> {
    if (response.isSuccessful) {
        return Single.just(RequestResult(response.body()!!, response.code()))
    } else {
        throw HttpException(response)
    }
}

fun <T> transformEmptyResponse(response: Response<T>): Completable {
    if (response.isSuccessful) {
        return Completable.complete()
    } else {
        throw HttpException(response)
    }
}

И

fun linkDevice(): Single<UserDevice> {
    val deviceInfo = deviceUtil.getDeviceInfo()

    return devicesService
        .linkDevice(deviceInfo)
        .flatMap { transformResponse(it) }
        .flatMap { requestResult ->
            requestResult.data.let { userDevice ->
                userPreferences.setDeviceId(userDevice.id)
                when (requestResult.code) {
                    200 -> {
                        // TODO: Analytics
                    }
                    201 -> {
                        // TODO: Analytics
                    }
                }

                Single.just(userDevice)
            }
        }
        .onErrorResumeNext { e ->
            val transformedException = transformRequestException(e) { httpException ->
                return@transformRequestException when (httpException.code()) {
                    409 -> DeviceAlreadyLinkedException()
                    else -> null
                }
            }
            Single.error(transformedException)
        }
}

Похоже, взломать, но я не нашел лучшего решения, и он работает.

...