I am trying to show quote on my app via an api. I have updated all the dependencies, plugins and libraries. I tried with a dummy api, the result was getting updated in the app then I tried with another quote api, there i found that some issue with the api but not in my code. But when I am using this api, I am facing this error -
Error fetching quote
kotlinx.serialization.SerializationException: Serializer for class 'QuoteResponse' is not found.
Please ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied.
at kotlinx.serialization.internal.Platform_commonKt.serializerNotRegistered(Platform.common.kt:90 undefined)
at kotlinx.serialization.SerializersKt__SerializersKt.serializer(Serializers.kt:299 undefined)
at kotlinx.serialization.SerializersKt.serializer(Unknown Source:1)
at io.ktor.serialization.kotlinx.SerializerLookupKt.serializerForTypeInfo(SerializerLookup.kt:29 undefined)
at io.ktor.serialization.kotlinx.KotlinxSerializationConverter.deserialize(KotlinxSerializationConverter.kt:77 undefined)
at io.ktor.serialization.ContentConverterKt$deserialize$inlined$map$1$2.emit(Emitters.kt:224 undefined)
at kotlinx.coroutines.flow.FlowKt__BuildersKt$asFlow$inlined$unsafeFlow$3.collect(SafeCollector.common.kt:116 undefined)
at io.ktor.serialization.ContentConverterKt$deserialize$inlined$map$1.collect(SafeCollector.common.kt:113 undefined)
at kotlinx.coroutines.flow.FlowKt__ReduceKt.firstOrNull(Reduce.kt:243 undefined)
at kotlinx.coroutines.flow.FlowKt.firstOrNull(Unknown Source:1)
at io.ktor.serialization.ContentConverterKt.deserialize(ContentConverter.kt:123 undefined)
at io.ktor.client.plugins.contentnegotiation.ContentNegotiation.convertResponse$ktor_client_content_negotiation(ContentNegotiation.kt:230 undefined)
at io.ktor.client.plugins.contentnegotiation.ContentNegotiation$Plugin$install$2.invokeSuspend(ContentNegotiation.kt:262 undefined)
at io.ktor.client.plugins.contentnegotiation.ContentNegotiation$Plugin$install$2.invoke(Unknown Source:13)
at io.ktor.client.plugins.contentnegotiation.ContentNegotiation$Plugin$install$2.invoke(Unknown Source:6)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120 undefined)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78 undefined)
at io.ktor.client.HttpClient$4.invokeSuspend(HttpClient.kt:177 undefined)
at io.ktor.client.HttpClient$4.invoke(Unknown Source:11)
at io.ktor.client.HttpClient$4.invoke(Unknown Source:6)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120 undefined)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78 undefined)
at io.ktor.util.pipeline.SuspendFunctionGun.proceedWith(SuspendFunctionGun.kt:88 undefined)
at io.ktor.client.plugins.HttpCallValidator$Companion$install$2.invokeSuspend(HttpCallValidator.kt:142 undefined)
at io.ktor.client.plugins.HttpCallValidator$Companion$install$2.invoke(Unknown Source:13)
at io.ktor.client.plugins.HttpCallValidator$Companion$install$2.invoke(Unknown Source:6)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120 undefined)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78 undefined)
at io.ktor.util.pipeline.SuspendFunctionGun.execute$ktor_utils(SuspendFunctionGun.kt:98 undefined)
at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:77 undefined)
at io.ktor.client.call.HttpClientCall.bodyNullable(HttpClientCall.kt:89 undefined)
at com.satpati.stutu.externalapi.QuoteApiKt$fetchQuote$2.invokeSuspend(QuoteApi.kt:50 undefined)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33 undefined)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108 undefined)
at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:115 undefined)
at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:103 undefined)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584 undefined)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793 undefined)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697 undefined)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684 undefined)
I have added this in my project level gradle plugins -
alias(libs.plugins.kotlin.serialization)
i have added this in my app level gradle dependencies -
implementation(libs.ktor.client.core)
implementation(libs.ktor.client.cio)
implementation(libs.ktor.client.content.negotiation)
implementation(libs.ktor.serialization.kotlinx.json)
implementation(libs.kotlinx.serialization.json)
this is my toml file -
[versions]
ktor = "2.3.4"
kotlinx-serialization = "1.7.3"
[libraries]
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" }
ktor-client-content-negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" }
ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" }
[plugins]
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
this is my data class -
@Serializable
data class QuoteResponse(
val id: Int,
val quote: String,
val author: String
)
this is my quoteApi -
val client = HttpClient(CIO) {
install(ContentNegotiation) {
json()
}
}
suspend fun fetchQuote(): String {
return withContext(Dispatchers.IO) {
try {
val url = "https://dummyjson.com/quotes/random"
val response = client.get(url)
// Handle non-successful responses (like 429)
if (!response.status.isSuccess()) {
Log.e("QuoteFetch", "HTTP Error: ${response.status}")
return@withContext "API limit reached. Try again later."
}
val quoteResponse: QuoteResponse = response.body()
quoteResponse.quote
} catch (e: Exception) {
Log.e("QuoteFetch", "Error fetching quote", e)
"Unable to fetch quote."
}
}
}
Can you please help me in finding what am I missing here.
You didn't apply the serialization plugin correctly.
You need to add this to the build gradle file of the module where you want to access serialization:
alias(libs.plugins.kotlin.serialization)
And in your project build gradle file you should only declare the plugin but not apply it, like this:
alias(libs.plugins.kotlin.serialization) apply false
After a Gradle sync everything should work now.
Unrelated, but:
withContext(Dispatchers.IO)
, Ktor does this on its own under the hood (as it should be - dispatcher switches should only occur where it is actually needed). Since your code does no IO itself, there is no need for you to switch the dispatcher.2.3.4
. At the time of writing the current version is 3.1.3
. You should update that. And while you're at it you should update the serialization plugin as well.