困ったこと
Ktor使用時、POSTメソッドでJSONを受け取った際、データの中身を受け取ることができなかった
構成
- ktor_version=1.5.1
- kotlin_version=1.4.21
- exposedVersion=0.31.1
ソースコード
Application.kt
fun main(args: Array<String>): Unit = io.ktor.server.netty.EngineMain.main(args)
@Suppress("unused") // Referenced in application.conf
@kotlin.jvm.JvmOverloads
fun Application.module(testing: Boolean = false) {
install(Locations) {
}
install(ContentNegotiation) {
jackson {
enable(SerializationFeature.INDENT_OUTPUT)
}
}
routing {
userController(userService) // ここでコントローラーを呼び出す
}
}
UserController.kt
fun Routing.userController() {
data class UserRegisterLocation(val name: String, val email: String)
post("/user"){
val registerRequest = call.receive<UserRegisterLocation>()
val request = RegisterUserRequest(registerRequest.name, registerRequest.email)
call.respond("status" to "OK")
}
}
このように書けば、registerRequest
変数でUserRegisterLocation型のデータを受け取れると思ったが、
curl -H 'Content-Type:application/json' -X POST -d '{\"name\":\"test\", \"email\":\"test@example.com\"}' http://localhost:8080/user
のようにリクエストを送信するとログに以下のように表示される
[eventLoopGroupProxy-4-1 @call-handler#3] INFO Application - Unhandled: POST - /user, io failed
解決策
公式のドキュメントを読むと、クラスはトップレベルで定義する必要があるということらしい。
そこで、UserController.kt
内でUserRegisterLocationをuserController関数内で定義していたものを、トップレベルで定義するように変更すると
UserController.kt(修正後)
// data classをトップレベルで定義する
data class UserRegisterLocation(val name: String, val email: String)
fun Routing.userController() {
post("/user"){
val registerRequest = call.receive<UserRegisterLocation>()
val request = RegisterUserRequest(registerRequest.name, registerRequest.email)
call.respond("status" to "OK")
}
}
TRACE Application - 200 OK: POST - /user
と返ってきた