diff --git a/androidApp/src/main/java/jp/co/soramitsu/xnetworking/android/NetworkService.kt b/androidApp/src/main/java/jp/co/soramitsu/xnetworking/android/NetworkService.kt index 28a5089e..afa0ce3d 100644 --- a/androidApp/src/main/java/jp/co/soramitsu/xnetworking/android/NetworkService.kt +++ b/androidApp/src/main/java/jp/co/soramitsu/xnetworking/android/NetworkService.kt @@ -1,12 +1,10 @@ package jp.co.soramitsu.appxnetworking -import androidx.constraintlayout.solver.state.State.Chain import jp.co.soramitsu.xnetworking.android.ChainInfoConstants import jp.co.soramitsu.xnetworking.lib.datasources.blockexplorer.api.BlockExplorerRepository import jp.co.soramitsu.xnetworking.lib.datasources.blockexplorer.api.models.AssetInfo import jp.co.soramitsu.xnetworking.lib.engines.rest.api.RestClient -import jp.co.soramitsu.xnetworking.lib.engines.rest.api.models.AbstractRestServerRequest -import kotlinx.serialization.DeserializationStrategy +import jp.co.soramitsu.xnetworking.lib.engines.utils.JsonGetRequest import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.builtins.ListSerializer @@ -18,12 +16,16 @@ class NetworkService( ) { suspend fun getRequest() = restClient.get( - SimpleJSONGetRequestHolder(url = "https://www.github.com") + request = JsonGetRequest( + url = "https://www.github.com", + responseDeserializer = ListSerializer(AssetRemote.serializer()) + ) ) suspend fun getAssets() = restClient.get( - SimpleJSONGetRequestHolder( - url = "https://raw.githubusercontent.com/soramitsu/fearless-utils/android/v2/chains/assets.json" + request = JsonGetRequest( + url = "https://raw.githubusercontent.com/soramitsu/fearless-utils/android/v2/chains/assets.json", + responseDeserializer = ListSerializer(AssetRemote.serializer()) ) ) @@ -82,11 +84,6 @@ class NetworkService( // } } -private data class SimpleJSONGetRequestHolder( - override val url: String, - override val responseDeserializer: DeserializationStrategy> = ListSerializer(AssetRemote.serializer()) -): AbstractRestServerRequest>() - @Serializable data class AssetRemote( @SerialName("id") diff --git a/gradle.properties b/gradle.properties index 30d17de5..daca8968 100644 --- a/gradle.properties +++ b/gradle.properties @@ -28,6 +28,6 @@ apolloGraphQLVersion=3.8.2 sqlDelightVersion=1.5.5 ktorVersion=2.3.1 coroutineVersion=1.8.1 -libVersion=1.0.3 +libVersion=1.0.4 RELEASE_REPOSITORY_URL=https://nexus.iroha.tech/repository/maven-soramitsu/ \ No newline at end of file diff --git a/lib/src/commonMain/kotlin/jp/co/soramitsu/xnetworking/lib/engines/rest/api/RestClient.kt b/lib/src/commonMain/kotlin/jp/co/soramitsu/xnetworking/lib/engines/rest/api/RestClient.kt index 3ab4ef6e..f9590515 100644 --- a/lib/src/commonMain/kotlin/jp/co/soramitsu/xnetworking/lib/engines/rest/api/RestClient.kt +++ b/lib/src/commonMain/kotlin/jp/co/soramitsu/xnetworking/lib/engines/rest/api/RestClient.kt @@ -12,13 +12,13 @@ abstract class RestClient { @OptIn(ExperimentalObjCRefinement::class) @HiddenFromObjC - abstract suspend fun post( + abstract suspend fun post( request: AbstractRestServerRequest.WithBody ): T @OptIn(ExperimentalObjCRefinement::class) @HiddenFromObjC - abstract suspend fun get( + abstract suspend fun get( request: AbstractRestServerRequest ): T } \ No newline at end of file diff --git a/lib/src/commonMain/kotlin/jp/co/soramitsu/xnetworking/lib/engines/rest/api/models/AbstractRestServerRequest.kt b/lib/src/commonMain/kotlin/jp/co/soramitsu/xnetworking/lib/engines/rest/api/models/AbstractRestServerRequest.kt index 2e8014f2..5ee73b5b 100644 --- a/lib/src/commonMain/kotlin/jp/co/soramitsu/xnetworking/lib/engines/rest/api/models/AbstractRestServerRequest.kt +++ b/lib/src/commonMain/kotlin/jp/co/soramitsu/xnetworking/lib/engines/rest/api/models/AbstractRestServerRequest.kt @@ -5,8 +5,9 @@ import kotlinx.serialization.DeserializationStrategy import kotlinx.serialization.Transient import kotlin.experimental.ExperimentalObjCRefinement import kotlin.native.HiddenFromObjC +import kotlin.reflect.KClass -abstract class AbstractRestServerRequest { +abstract class AbstractRestServerRequest { open val bearerToken: String? = null @@ -25,8 +26,14 @@ abstract class AbstractRestServerRequest { @Transient abstract val responseDeserializer: DeserializationStrategy + @OptIn(ExperimentalObjCRefinement::class) + @HiddenFromObjC + @Transient + abstract val responseClazz: KClass + /** * Specific Implementation of equals that ignores @param #responseDeserializer + * and @param #responseClazz */ override fun equals(other: Any?): Boolean { if (other !is AbstractRestServerRequest<*>) @@ -65,7 +72,7 @@ abstract class AbstractRestServerRequest { return super.hashCode() } - abstract class WithBody: AbstractRestServerRequest() { + abstract class WithBody: AbstractRestServerRequest() { abstract val requestContentType: RestClient.ContentType diff --git a/lib/src/commonMain/kotlin/jp/co/soramitsu/xnetworking/lib/engines/rest/impl/RestClientImpl.kt b/lib/src/commonMain/kotlin/jp/co/soramitsu/xnetworking/lib/engines/rest/impl/RestClientImpl.kt index 76a0405c..3f6b8a26 100644 --- a/lib/src/commonMain/kotlin/jp/co/soramitsu/xnetworking/lib/engines/rest/impl/RestClientImpl.kt +++ b/lib/src/commonMain/kotlin/jp/co/soramitsu/xnetworking/lib/engines/rest/impl/RestClientImpl.kt @@ -1,9 +1,5 @@ package jp.co.soramitsu.xnetworking.lib.engines.rest.impl -import io.ktor.client.plugins.ClientRequestException -import io.ktor.client.plugins.RedirectResponseException -import io.ktor.client.plugins.ResponseException -import io.ktor.client.plugins.ServerResponseException import io.ktor.client.request.accept import io.ktor.client.request.bearerAuth import io.ktor.client.request.get @@ -24,6 +20,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import kotlinx.serialization.DeserializationStrategy import kotlinx.serialization.SerializationException +import kotlin.reflect.KClass class RestClientImpl( private val restClientConfig: AbstractRestClientConfig @@ -31,8 +28,11 @@ class RestClientImpl( private val client by httpClientBuilder { restClientConfig } - override suspend fun post(request: AbstractRestServerRequest.WithBody): T = - requestCatchingAndDeserialize(request.responseDeserializer) { + override suspend fun post(request: AbstractRestServerRequest.WithBody): T = + requestCatchingAndDeserialize( + deserializer = request.responseDeserializer, + clazz = request.responseClazz + ) { client.post(request.url) { if (request.requestContentType === ContentType.JSON) contentType(io.ktor.http.ContentType.Application.Json) @@ -58,8 +58,11 @@ class RestClientImpl( }.bodyAsText() } - override suspend fun get(request: AbstractRestServerRequest): T = - requestCatchingAndDeserialize(request.responseDeserializer) { + override suspend fun get(request: AbstractRestServerRequest): T = + requestCatchingAndDeserialize( + deserializer = request.responseDeserializer, + clazz = request.responseClazz + ) { client.get(request.url) { request.bearerToken.apply { if (!this.isNullOrBlank()) @@ -84,16 +87,22 @@ class RestClientImpl( }.bodyAsText() } - private suspend fun requestCatchingAndDeserialize( + private suspend fun requestCatchingAndDeserialize( deserializer: DeserializationStrategy, + clazz: KClass, block: suspend () -> String ) = withContext(Dispatchers.Default) { try { + val value = withContext(Dispatchers.CommonIO) { block.invoke() } + + if (clazz == String::class) { + @Suppress("UNCHECKED_CAST") + return@withContext value as T + } + restClientConfig.getOrCreateJsonConfig().decodeFromString( deserializer = deserializer, - string = withContext(Dispatchers.CommonIO) { - block.invoke() - } + string = value ) } catch (e: RestClientException.WithCode) { throw e diff --git a/lib/src/commonMain/kotlin/jp/co/soramitsu/xnetworking/lib/engines/utils/JsonRequestWrappers.kt b/lib/src/commonMain/kotlin/jp/co/soramitsu/xnetworking/lib/engines/utils/JsonRequestWrappers.kt index f72f2040..cd34070d 100644 --- a/lib/src/commonMain/kotlin/jp/co/soramitsu/xnetworking/lib/engines/utils/JsonRequestWrappers.kt +++ b/lib/src/commonMain/kotlin/jp/co/soramitsu/xnetworking/lib/engines/utils/JsonRequestWrappers.kt @@ -5,22 +5,100 @@ import jp.co.soramitsu.xnetworking.lib.engines.rest.api.models.AbstractRestServe import kotlinx.serialization.DeserializationStrategy import kotlin.experimental.ExperimentalObjCRefinement import kotlin.native.HiddenFromObjC +import kotlin.reflect.KClass +@Suppress("FunctionName") @OptIn(ExperimentalObjCRefinement::class) @HiddenFromObjC -class JsonPostRequest( - override val url: String, - override val body: Any, - override val responseDeserializer: DeserializationStrategy -): AbstractRestServerRequest.WithBody() { +inline fun JsonPostRequest( + url: String, + body: Any, + userAgent: String? = null, + bearerToken: String? = null, + headers: Map? = null, + responseDeserializer: DeserializationStrategy +) = JsonPostRequestNonReified( + url = url, + body = body, + userAgent = userAgent, + bearerToken = bearerToken, + headers = headers, + responseDeserializer = responseDeserializer, + responseClazz = Response::class +) + +@Suppress("FunctionName") +@OptIn(ExperimentalObjCRefinement::class) +@HiddenFromObjC +fun JsonPostRequestNonReified( + url: String, + body: Any, + userAgent: String? = null, + bearerToken: String? = null, + headers: Map? = null, + responseDeserializer: DeserializationStrategy, + responseClazz: KClass +) = object : AbstractRestServerRequest.WithBody() { + override val bearerToken: String? = bearerToken + + override val url: String = url + + override val headers: Map? = headers + + override val userAgent: String? = userAgent + + override val body: Any = body + + override val responseDeserializer: DeserializationStrategy = responseDeserializer + + override val responseClazz: KClass = responseClazz + override val requestContentType: RestClient.ContentType = RestClient.ContentType.JSON } +@Suppress("FunctionName") @OptIn(ExperimentalObjCRefinement::class) @HiddenFromObjC -class JsonGetRequest( - override val url: String, - override val headers: Map? = null, - override val queryParams: Map? = null, - override val responseDeserializer: DeserializationStrategy -): AbstractRestServerRequest() \ No newline at end of file +inline fun JsonGetRequest( + url: String, + userAgent: String? = null, + bearerToken: String? = null, + headers: Map? = null, + queryParams: Map? = null, + responseDeserializer: DeserializationStrategy +) = JsonGetRequestNonReified( + url = url, + userAgent = userAgent, + bearerToken = bearerToken, + headers = headers, + queryParams = queryParams, + responseDeserializer = responseDeserializer, + responseClazz = Response::class +) + +@Suppress("FunctionName") +@OptIn(ExperimentalObjCRefinement::class) +@HiddenFromObjC +fun JsonGetRequestNonReified( + url: String, + userAgent: String? = null, + bearerToken: String? = null, + headers: Map? = null, + queryParams: Map? = null, + responseDeserializer: DeserializationStrategy, + responseClazz: KClass +) = object: AbstractRestServerRequest() { + override val bearerToken: String? = bearerToken + + override val url: String = url + + override val headers: Map? = headers + + override val userAgent: String? = userAgent + + override val queryParams: Map? = queryParams + + override val responseDeserializer: DeserializationStrategy = responseDeserializer + + override val responseClazz: KClass = responseClazz +} \ No newline at end of file diff --git a/lib/src/iosMain/kotlin/jp/co/soramitsu/xnetworking/lib/engines/utils/JsonRequestWrappers.kt b/lib/src/iosMain/kotlin/jp/co/soramitsu/xnetworking/lib/engines/utils/JsonRequestWrappers.kt index 5522b72a..120edfdd 100644 --- a/lib/src/iosMain/kotlin/jp/co/soramitsu/xnetworking/lib/engines/utils/JsonRequestWrappers.kt +++ b/lib/src/iosMain/kotlin/jp/co/soramitsu/xnetworking/lib/engines/utils/JsonRequestWrappers.kt @@ -5,6 +5,7 @@ import jp.co.soramitsu.xnetworking.lib.engines.rest.api.models.AbstractRestServe import kotlinx.serialization.DeserializationStrategy import kotlinx.serialization.builtins.serializer import kotlin.experimental.ExperimentalObjCName +import kotlin.reflect.KClass @OptIn(ExperimentalObjCName::class) @@ -12,9 +13,10 @@ import kotlin.experimental.ExperimentalObjCName class JsonGetRequestIOS( override val url: String, override val headers: Map? = null, - override val queryParams: Map? = null, + override val queryParams: Map? = null ): AbstractRestServerRequest() { override val responseDeserializer: DeserializationStrategy = String.serializer() + override val responseClazz: KClass = String::class } @OptIn(ExperimentalObjCName::class) @@ -25,4 +27,5 @@ class JsonPostRequestIOS( ): AbstractRestServerRequest.WithBody() { override val requestContentType: RestClient.ContentType = RestClient.ContentType.JSON override val responseDeserializer: DeserializationStrategy = String.serializer() + override val responseClazz: KClass = String::class } \ No newline at end of file