首页 > 解决方案 > Ktor Location API:将 JSON 映射到通用 Map 对象

问题描述

当我将常规路由 API 与 GSON 一起使用时,我可以使用以下代码片段将 JSON 参数反序列化为 Map<String, Any>:

        post("/books") {
            val request = call.receive<Map<String, Any>>()
            ...
        }

在我的例子中,请求是 com.google.gson.internal.LinkedTreeMap 的一个实例。

有没有办法使用 Location API 来做同样的事情?当我用具体成员定义数据类但我找不到使用地图的方法时,它工作正常。我正在尝试以下几件事:

@Location ("/books")
<some magic class definition>

fun Application.bookModule() {
    routing {
        post<BookRequest> {
            val request = call.receive<BookRequest>()
            ...
        }

但我还没有想出任何可行的方法。帮助?

标签: ktor

解决方案


位置仅代表端点的路径和查询参数,因此无法根据请求正文进行路由。位置类的属性应该映射到路径段,例如

@Location ("/books/{title}/{author}") data class BookRequest(
    val title: String,
    val author: String,
)

要接收请求正文并将其转换为对象,只需使用ContentNegotiation 插件。以下是对curl -v --header "Content-Type: application/json" --request POST --data '{"title":"Hitchhiker", "author":"DNA", "detail":{"foo": "bar"}}' http://localhost:8080/books请求响应 200 OK 的服务器示例:

import io.ktor.application.*
import io.ktor.features.*
import io.ktor.gson.*
import io.ktor.http.*
import io.ktor.locations.*
import io.ktor.locations.post
import io.ktor.request.*
import io.ktor.response.*
import io.ktor.routing.routing
import io.ktor.server.engine.*
import io.ktor.server.netty.*

fun main(args: Array<String>) {
    embeddedServer(Netty, port = 8080) {
        install(ContentNegotiation) {
            gson()
        }
        install(Locations)
        bookModule()
    }.start()
}

fun Application.bookModule() {
    routing {
        post<BookRequest> {
            val request = call.receive<Map<String, Any>>()
            println(request)
            call.respond(HttpStatusCode.OK)
        }
    }
}

@Location ("/books") class BookRequest

推荐阅读