Farid Benhaimoud
09/03/2023, 6:31 PMroute(path = "/login") {
post {
val params = call.receive<SignInParams>()
val result = repository.signIn(params = params)
call.respond(
message = result
)
}
}
This is the stacktrace
2023-09-03 20:28:51.996 [eventLoopGroupProxy-4-1] ERROR ktor.application - Unhandled: POST - /login
kotlinx.serialization.SerializationException: Serializer for class 'Result' 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:92)
at kotlinx.serialization.SerializersKt__SerializersKt.serializer(Serializers.kt:285)
at kotlinx.serialization.SerializersKt.serializer(Unknown Source)
at io.ktor.serialization.kotlinx.SerializerLookupKt.guessSerializer(SerializerLookup.kt:50)
at io.ktor.serialization.kotlinx.KotlinxSerializationConverter.serializeNullable(KotlinxSerializationConverter.kt:66)
at io.ktor.server.plugins.contentnegotiation.ResponseConverterKt$convertResponseBody$1$2.invokeSuspend(ResponseConverter.kt:66)
at io.ktor.server.plugins.contentnegotiation.ResponseConverterKt$convertResponseBody$1$2.invoke(ResponseConverter.kt)
at io.ktor.server.plugins.contentnegotiation.ResponseConverterKt$convertResponseBody$1$2.invoke(ResponseConverter.kt)
at io.ktor.server.application.OnCallRespondContext.transformBody(KtorCallContexts.kt:86)
at io.ktor.server.plugins.contentnegotiation.ResponseConverterKt$convertResponseBody$1.invokeSuspend(ResponseConverter.kt:39)
at io.ktor.server.plugins.contentnegotiation.ResponseConverterKt$convertResponseBody$1.invoke(ResponseConverter.kt)
at io.ktor.server.plugins.contentnegotiation.ResponseConverterKt$convertResponseBody$1.invoke(ResponseConverter.kt)
at io.ktor.server.application.PluginBuilder$onDefaultPhase$1.invokeSuspend(PluginBuilder.kt:215)
at io.ktor.server.application.PluginBuilder$onDefaultPhase$1.invoke(PluginBuilder.kt)
at io.ktor.server.application.PluginBuilder$onDefaultPhase$1.invoke(PluginBuilder.kt)
at io.ktor.server.application.PluginBuilder$onDefaultPhaseWithMessage$1$1$1.invokeSuspend(PluginBuilder.kt:198)
at io.ktor.server.application.PluginBuilder$onDefaultPhaseWithMessage$1$1$1.invoke(PluginBuilder.kt)
at io.ktor.server.application.PluginBuilder$onDefaultPhaseWithMessage$1$1$1.invoke(PluginBuilder.kt)
at io.ktor.util.debug.ContextUtilsKt$addToContextInDebugMode$2.invokeSuspend(ContextUtils.kt:33)
at io.ktor.util.debug.ContextUtilsKt$addToContextInDebugMode$2.invoke(ContextUtils.kt)
at io.ktor.util.debug.ContextUtilsKt$addToContextInDebugMode$2.invoke(ContextUtils.kt)
at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:89)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.withContext(Builders.common.kt:169)
at kotlinx.coroutines.BuildersKt.withContext(Unknown Source)
at io.ktor.util.debug.ContextUtilsKt.addToContextInDebugMode(ContextUtils.kt:33)
at io.ktor.server.application.PluginBuilder$onDefaultPhaseWithMessage$1$1.invokeSuspend(PluginBuilder.kt:194)
at io.ktor.server.application.PluginBuilder$onDefaultPhaseWithMessage$1$1.invoke(PluginBuilder.kt)
at io.ktor.server.application.PluginBuilder$onDefaultPhaseWithMessage$1$1.invoke(PluginBuilder.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78)
at io.ktor.util.pipeline.SuspendFunctionGun.execute$ktor_utils(SuspendFunctionGun.kt:98)
at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:77)
at com.talamyd.auth.AuthRouteKt$authRouting$2$1.invokeSuspend(AuthRoute.kt:80)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at io.netty.util.concurrent.AbstractEventExecutor.runTask$$$capture(AbstractEventExecutor.java:174)
at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute$$$capture(AbstractEventExecutor.java:167)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:470)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:569)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.ktor.server.netty.EventLoopGroupProxy$Companion.create$lambda$1$lambda$0(NettyApplicationEngine.kt:296)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:833)
Any help is appreciatedBerkay Özkan
09/03/2023, 6:34 PMPlease ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied.
Farid Benhaimoud
09/03/2023, 6:36 PMFarid Benhaimoud
09/03/2023, 6:38 PMBerkay Özkan
09/03/2023, 6:39 PMFarid Benhaimoud
09/03/2023, 6:42 PMsuspend fun signIn(request: SignInRequest): Result<AuthResponseData> = <http://client.post|client.post> {
endPoint("login")
setBody(request)
}.body()
Berkay Özkan
09/03/2023, 6:44 PMsuspend fun signIn(request: SignInRequest): AuthResponseData = <http://client.post|client.post> {
endPoint("login")
setBody(request)
}.body()
You can directly deserialize to AuthResponseDataBerkay Özkan
09/03/2023, 6:44 PMFarid Benhaimoud
09/03/2023, 6:46 PMBerkay Özkan
09/03/2023, 6:50 PMResult
wrapping, If you are intended to use benefits of result then you can use
route(path = "/login") {
post {
val params = call.receive<SignInParams>()
val result = repository.signIn(params = params)
call.respond(
message = result.getOrNull()
)
}
}
Christos Malliaridis
09/04/2023, 3:46 AMResult
is intended to be transferred over the internet or should be used as a wrapper for actions that may be successful or not.
Normally what I do is I use serializable data classes that are my data transfer objects (DTOs) and send those over the internet. Any client (and server) that executes an action that may be successful or may fail (typically in the repositories, e.g. a GET
request) returns a Result
, either with or without data (Unit
in that case). If it fails, the result contains the error that occurred (e.g. timeout, server unreachable, internal server error etc.) and I can handle it accordingly. If it succeeds, I get the data / I am sure that the action was executed successful and I can proceed.
Please note that in your example (server side), a failed result should be represented with the according HTTP status code in the response, typically a 4XX, rather than a successful response (2XX) with an error in the body. Latter is common (bad) practice I have seen in many applications that I do not recommend personally.Farid Benhaimoud
09/04/2023, 9:02 AM