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 PMserialization()
part)receive
ContentType.Any
/foo/{date}/{titleSlug}?redirectTo=bar
e5l
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 PMjson
e5l
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.get
e5l
07/20/2020, 2:41 PMimport io.ktor.serialization.*
could you add that one?addamsson
07/20/2020, 2:42 PMe5l
07/20/2020, 2:49 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")
}
}
}
}
<http://localhost:8080/foo/2018-10-21/wtf-is-this.html>
try/catch
and this is what i'm getting:io.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)
e5l
07/20/2020, 3:04 PMaddamsson
07/20/2020, 3:06 PMe5l
07/20/2020, 3:07 PMLocation
for thataddamsson
07/20/2020, 3:07 PMe5l
07/20/2020, 3:07 PMaddamsson
07/20/2020, 3:07 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?nschulzke
07/20/2020, 3:15 PMaddamsson
07/20/2020, 3:17 PMContentNegotiation
with forms?call.parameters
seems to include query parameters as wellnschulzke
07/20/2020, 3:17 PMaddamsson
07/20/2020, 3:17 PMnschulzke
07/20/2020, 3:18 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 PMe5l
07/20/2020, 3:20 PMContentNegotations
compatibilityaddamsson
07/20/2020, 3:22 PMreceiveAs()
method for the time being on the Parameters
classnschulzke
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 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.receive
method and just register a new ContentConverter
.addamsson
07/20/2020, 6:22 PM