moko-network
Библиотека moko-network предоставляет компоненты для работы с сетью в Kotlin Multiplatform: генерацию сущностей и API-классов из OpenAPI (Swagger) спецификаций, а также набор Ktor-плагинов для типовых задач.
Состав библиотеки
Библиотека состоит из нескольких модулей:
network— базовый модуль с Ktor-плагинами (ExceptionFeature,TokenFeature,RefreshTokenFeature,LanguageFeature);network-generator— Gradle-плагин для генерации кода из OpenAPI;network-errors— интеграция сmoko-errorsдля обработки сетевых ошибок;network-engine— предварительно сконфигурированныйHttpClientEngine;network-bignum— сериализатор дляBigInteger/BigDecimal.
OpenAPI code generation
Для генерации кода подключите плагин и укажите путь к OpenAPI спецификации.
Подключение плагина
buildscript {
dependencies {
classpath "dev.icerock.moko:network-generator:0.23.0"
}
}
apply plugin: "dev.icerock.mobile.multiplatform-network-generator"
Конфигурация спецификации
mokoNetwork {
spec("pets") {
inputSpec = file("src/swagger.json")
}
spec("news") {
inputSpec = file("src/newsApi.yaml")
packageName = "news"
isInternal = false
isOpen = true
enumFallbackNull = false
}
}
После запуска Gradle-задачи openApiGenerate сгенерированные классы появятся в build/generated/moko-network.
Использование в коде
import dev.icerock.moko.network.generated.models.*
import dev.icerock.moko.network.generated.apis.*
class TestViewModel : ViewModel() {
private val petApi = PetApi(
basePath = "https://petstore.swagger.io/v2/",
httpClient = ktorHttpClient,
json = kotlinxJsonParser
)
fun apiRequest() {
viewModelScope.launch {
val pet = petApi.findPetsByStatus(listOf("available"))
}
}
}
Флаг enumFallbackNull = true включает генерацию обёртки Safeable для enum-свойств — при неожиданном значении вернётся null.
Features (Ktor-плагины)
Плагины moko-network реализуют интерфейс HttpClientFeature (Ktor 2.x — HttpClientPlugin).
ExceptionFeature
Проверяет статус ответа сервера. Если статус неуспешный — генерирует исключение на основе тела ответа.
override fun install(feature: ExceptionFeature, scope: HttpClient) {
scope.responsePipeline.intercept(HttpResponsePipeline.Receive) { (_, body) ->
if (body !is ByteReadChannel) return@intercept
val response = context.response
if (!response.status.isSuccess()) {
val packet = body.readRemaining()
val responseString = packet.readText(charset = Charset.forName("UTF-8"))
throw feature.exceptionFactory.createException(
request = context.request,
response = context.response,
responseBody = responseString
)
}
proceedWith(subject)
}
}
LanguageFeature
Добавляет заголовок с языком к каждому запросу, чтобы сервер мог вернуть ответ на нужном языке.
override fun install(feature: LanguageFeature, scope: HttpClient) {
scope.requestPipeline.intercept(HttpRequestPipeline.State) {
feature.languageProvider.getLanguageCode()?.apply {
context.header(feature.languageHeaderName, this)
}
}
}
TokenFeature
Добавляет токен авторизации к каждому запросу. Для использования необходимо реализовать getToken().
override fun install(feature: TokenFeature, scope: HttpClient) {
scope.requestPipeline.intercept(HttpRequestPipeline.State) {
feature.tokenProvider.getToken()?.apply {
context.headers.remove(feature.tokenHeaderName)
context.header(feature.tokenHeaderName, this)
}
}
}
RefreshTokenFeature
Обрабатывает ответ 401 Unauthorized: обновляет токен через updateTokenHandler и повторяет запрос. Если несколько запросов получили 401 одновременно — проверяется актуальность токена через isCredentialsActual, и лишние обновления не выполняются.
if (!feature.isCredentialsActual(context.request)) {
val requestBuilder = HttpRequestBuilder().takeFrom(context.request)
val result: HttpResponse = context.client!!.request(requestBuilder)
proceedWith(result)
return@intercept
}
if (feature.updateTokenHandler.invoke()) {
val requestBuilder = HttpRequestBuilder().takeFrom(context.request)
val result: HttpResponse = context.client!!.request(requestBuilder)
proceedWith(result)
} else {
proceedWith(subject)
}
moko-network-errors
Модуль network-errors предоставляет встроенные мапперы для преобразования исключений moko-network в StringDesc (тексты на русском и английском).