addamsson
07/20/2020, 2:34 PMContentNegotiation feature? I've been banging my head against the wall for ours and it is still not working for me. I have parameter classes with the @Searializable annotation:
@Serializable
data class ShowPostURL(
val date: String,
val titleSlug: String,
override val redirectTo: String? = null
)
and no matter what I do call.receive() won't work. I'm getting HTTP 415 errors and Ktor doesn't even log anything. I've added the serialization support as well:
install(ContentNegotiation) {
json
}
How do I fix this? This is how I'm trying to use it:
accept(ContentType.Any) {
get(operation.route) {
val input = call.receive(ShowPostURL::class)
call.respondText("foo")
}
}e5l
07/20/2020, 2:35 PMaddamsson
07/20/2020, 2:36 PMaddamsson
07/20/2020, 2:36 PMserialization() part)addamsson
07/20/2020, 2:37 PMreceiveaddamsson
07/20/2020, 2:37 PMaddamsson
07/20/2020, 2:38 PMContentType.Anyaddamsson
07/20/2020, 2:38 PMaddamsson
07/20/2020, 2:38 PMaddamsson
07/20/2020, 2:39 PM/foo/{date}/{titleSlug}?redirectTo=bare5l
07/20/2020, 2:39 PMinstall(ContentNegotiation) {
json()
}addamsson
07/20/2020, 2:39 PMreceive()e5l
07/20/2020, 2:39 PM() after json?addamsson
07/20/2020, 2:39 PMaddamsson
07/20/2020, 2:39 PMjsonaddamsson
07/20/2020, 2:40 PMe5l
07/20/2020, 2:40 PMaddamsson
07/20/2020, 2:40 PMimport io.ktor.application.call
import io.ktor.http.ContentType
import io.ktor.request.receive
import io.ktor.response.respondText
import io.ktor.routing.Routing
import io.ktor.routing.accept
import io.ktor.routing.gete5l
07/20/2020, 2:41 PMimport io.ktor.serialization.* could you add that one?addamsson
07/20/2020, 2:42 PMaddamsson
07/20/2020, 2:42 PMe5l
07/20/2020, 2:49 PMaddamsson
07/20/2020, 2:54 PMaddamsson
07/20/2020, 2:54 PMimport io.ktor.application.Application
import io.ktor.application.call
import io.ktor.application.install
import io.ktor.features.ContentNegotiation
import io.ktor.http.ContentType
import io.ktor.request.receive
import io.ktor.response.respondText
import io.ktor.routing.accept
import io.ktor.routing.get
import io.ktor.routing.routing
import io.ktor.serialization.json
import io.ktor.server.engine.applicationEngineEnvironment
import io.ktor.server.engine.connector
import io.ktor.server.engine.embeddedServer
import io.ktor.server.netty.Netty
import kotlinx.serialization.Serializable
fun main(args: Array<String>) {
val env = applicationEngineEnvironment {
module {
example()
}
connector {
port = 8080
host = "0.0.0.0"
}
}
embeddedServer(Netty, env).apply {
start(wait = true)
}
}
@Serializable
data class PostURL(
val date: String,
val titleSlug: String,
val redirectTo: String? = null
)
fun Application.example() {
install(ContentNegotiation) {
json()
}
routing {
accept(ContentType.Any) {
get("/foo/{date}/{titleSlug}") {
val input = call.receive(PostURL::class)
println("$input was received.")
call.respondText("foo")
}
}
}
}addamsson
07/20/2020, 2:54 PM<http://localhost:8080/foo/2018-10-21/wtf-is-this.html>addamsson
07/20/2020, 2:54 PMaddamsson
07/20/2020, 2:58 PMaddamsson
07/20/2020, 3:02 PMtry/catch and this is what i'm getting:addamsson
07/20/2020, 3:02 PMio.ktor.features.UnsupportedMediaTypeException: Content type */* is not supported
at io.ktor.features.ContentNegotiation$Feature$install$3.invokeSuspend(ContentNegotiation.kt:167)
at io.ktor.features.ContentNegotiation$Feature$install$3.invoke(ContentNegotiation.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(PipelineContext.kt:318)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(PipelineContext.kt:163)
at io.ktor.util.pipeline.SuspendFunctionGun.execute(PipelineContext.kt:183)
at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:27)
at io.ktor.request.ApplicationReceiveFunctionsKt.receive(ApplicationReceiveFunctions.kt:110)
at io.ktor.request.ApplicationReceiveFunctionsKt.receive(ApplicationReceiveFunctions.kt:90)
at org.agorahq.agora.delivery.ExampleKt$example$2$2$1.invokeSuspend(Example.kt:54)
at org.agorahq.agora.delivery.ExampleKt$example$2$2$1.invoke(Example.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(PipelineContext.kt:318)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(PipelineContext.kt:163)
at io.ktor.util.pipeline.SuspendFunctionGun.execute(PipelineContext.kt:183)
at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:27)
at io.ktor.routing.Routing.executeResult(Routing.kt:147)
at io.ktor.routing.Routing.interceptor(Routing.kt:34)
at io.ktor.routing.Routing$Feature$install$1.invokeSuspend(Routing.kt:99)
at io.ktor.routing.Routing$Feature$install$1.invoke(Routing.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(PipelineContext.kt:318)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(PipelineContext.kt:163)
at io.ktor.features.ContentNegotiation$Feature$install$1.invokeSuspend(ContentNegotiation.kt:107)
at io.ktor.features.ContentNegotiation$Feature$install$1.invoke(ContentNegotiation.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(PipelineContext.kt:318)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(PipelineContext.kt:163)
at io.ktor.util.pipeline.SuspendFunctionGun.execute(PipelineContext.kt:183)
at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:27)
at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$2.invokeSuspend(DefaultEnginePipeline.kt:120)
at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$2.invoke(DefaultEnginePipeline.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(PipelineContext.kt:318)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(PipelineContext.kt:163)
at io.ktor.util.pipeline.SuspendFunctionGun.execute(PipelineContext.kt:183)
at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:27)
at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1.invokeSuspend(NettyApplicationCallHandler.kt:40)
at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1.invoke(NettyApplicationCallHandler.kt)
at kotlinx.coroutines.intrinsics.UndispatchedKt.startCoroutineUndispatched(Undispatched.kt:55)
at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:111)
at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:158)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:54)
at kotlinx.coroutines.BuildersKt.launch(Unknown Source)
at io.ktor.server.netty.NettyApplicationCallHandler.handleRequest(NettyApplicationCallHandler.kt:30)
at io.ktor.server.netty.NettyApplicationCallHandler.channelRead(NettyApplicationCallHandler.kt:24)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:377)
at io.netty.channel.AbstractChannelHandlerContext.access$600(AbstractChannelHandlerContext.java:59)
at io.netty.channel.AbstractChannelHandlerContext$7.run(AbstractChannelHandlerContext.java:368)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)addamsson
07/20/2020, 3:03 PMaddamsson
07/20/2020, 3:03 PMe5l
07/20/2020, 3:04 PMaddamsson
07/20/2020, 3:06 PMe5l
07/20/2020, 3:07 PMLocation for thate5l
07/20/2020, 3:07 PMaddamsson
07/20/2020, 3:07 PMaddamsson
07/20/2020, 3:07 PMaddamsson
07/20/2020, 3:07 PMaddamsson
07/20/2020, 3:08 PMe5l
07/20/2020, 3:08 PMaddamsson
07/20/2020, 3:08 PMe5l
07/20/2020, 3:08 PMaddamsson
07/20/2020, 3:08 PMe5l
07/20/2020, 3:08 PMaddamsson
07/20/2020, 3:09 PMnschulzke
07/20/2020, 3:10 PMaddamsson
07/20/2020, 3:12 PMcall.parameters and call.receiveParameters()? It is not clear from the docsnschulzke
07/20/2020, 3:13 PMreceiveParameters gets the request body as a Parameters object. call.parameters is what comes in in the URL. Not great naming.addamsson
07/20/2020, 3:14 PMreceiveParameters() is the alternative for receive() if you're not doing ContentNegotiation?addamsson
07/20/2020, 3:14 PMnschulzke
07/20/2020, 3:15 PMnschulzke
07/20/2020, 3:16 PMaddamsson
07/20/2020, 3:17 PMContentNegotiation with forms?addamsson
07/20/2020, 3:17 PMcall.parameters seems to include query parameters as wellnschulzke
07/20/2020, 3:17 PMnschulzke
07/20/2020, 3:17 PMaddamsson
07/20/2020, 3:17 PMaddamsson
07/20/2020, 3:18 PMnschulzke
07/20/2020, 3:18 PMnschulzke
07/20/2020, 3:19 PMreceiveParameters and parameters have the same type, you can deserialize both the same way, once you have a way to do one.addamsson
07/20/2020, 3:19 PMaddamsson
07/20/2020, 3:19 PMaddamsson
07/20/2020, 3:19 PMe5l
07/20/2020, 3:20 PMContentNegotations compatibilitye5l
07/20/2020, 3:20 PMaddamsson
07/20/2020, 3:22 PMaddamsson
07/20/2020, 3:22 PMreceiveAs() method for the time being on the Parameters classaddamsson
07/20/2020, 3:25 PMaddamsson
07/20/2020, 3:25 PMaddamsson
07/20/2020, 3:25 PMaddamsson
07/20/2020, 3:25 PMnschulzke
07/20/2020, 3:26 PMreceive method, if it's not I deserialize with receiveParameters and my extension.addamsson
07/20/2020, 3:26 PMnschulzke
07/20/2020, 3:27 PMPipelineContext<Unit, ApplicationCall>, so you don't have to have the checks everywhere.addamsson
07/20/2020, 3:27 PMaddamsson
07/20/2020, 3:27 PMnschulzke
07/20/2020, 3:30 PMPipelineContext<Unit, ApplicationCall>.myReceive(type: KClass<T>) {
if (request.contentType().match(ContentType.Application.Json) {
receive(type);
} else {
receiveParameters().myDeserialize(type);
}
}
So, if it's JSON, the extension acts as though it's just the receive method. Otherwise, it uses the custom deserialization.nschulzke
07/20/2020, 3:32 PMnschulzke
07/20/2020, 3:37 PMnschulzke
07/20/2020, 3:38 PMreceive method and just register a new ContentConverter.addamsson
07/20/2020, 6:22 PM