Я изо всех сил стараюсь поддерживать согласованные типы в моем приложении Kotlin для Retrofit, Room и RxJava2 из-за соглашения об именовании ключей JSON, которое использует API.Я попытался найти лучший способ решения проблемы ниже, но я не могу придумать лучшего способа ее решить, и мне интересно, что может предложить сообщество.
Рассмотримследующий пример:
Я использую язык Kotlin на Android и выполняю сетевые запросы с помощью Retrofit и GSON.Используемый мной API предоставляет JSON другое имя корневого ключа в зависимости от того, является ли ответ Array
или единственным Object
.
. Полезная нагрузка каждого Object
одинакова, но еслиответом является Array
, корневой ключ - множественное число.
Например, допустим, у меня есть класс данных, определенный для пользователя:
data class User(var id: Int?, name: String?)
Если я сделаю запрос APIдля одного пользователя API возвращает следующее:
{
"user": {
"id": 1,
"name: "Sam"
}
}
Если я делаю запрос API для нескольких пользователей, API возвращает следующее:
{
"users": [{
"id": 1,
"name: "Sam"
}]
}
Полезная нагрузка одинакова, но корневой ключ изменяется между user
и users
.Я создал класс данных для обработки отдельных корневых ключей:
data class Users(
@SerializedName("users") var users: List<User>?,
@SerializedName("user") var user: User?
)
И при выполнении отдельных запросов API я использую класс данных Users
для обоих типов:
/** GET single user by ID */
@GET("users/{id}")
fun getUser(
@Path("id") id: Int?): Single<Users>
/** GET list of users */
@GET("users")
fun getUsers(): Single<Users>
И когда я сохраняю ответ в базе данных Room, я получаю к нему доступ, используя response.users
или response.user
соответственно.Комната настроена на возврат запросов как User
или List<User>
, и это создает проблему при использовании запросов на модификацию в потоке RxJava2.Например, это очень простой поток, если база данных Room возвращает Maybe<List<User>>
:
usersRepository.getAll()
.switchIfEmpty(api.getUsers())
Результат usersRepository.getAll()
равен List<User>
, но если результат из базы данных пуст, и я пытаюсьвместо отката на запрос API, RxJava2 показывает ошибку Incompatible Type
, потому что запрос api.getUsers()
возвращает тип Single<Users>
, а не Single<List<User>>
.Если бы запрос API мог использовать тот же тип, у меня не было бы проблемы, но я не могу указать Single<List<User>>
в запросе на модификацию, потому что GSON не может десериализовать ответ правильно.
Из-за этого, исходя из моего текущего понимания вопроса (который может быть неспециалистом, и я готов к формированию), я разделяю запросы к базе данных и API и выполняю много empty
/ null
проверок, что мешает мне хранить все в одном хорошем и аккуратном потоке RxJava2.
Надеюсь, этот вопрос достаточно ясен, и я ценю чей-либо вклад.Спасибо за ваше время!