Hey there. I’m trying to get my head around Ktor2 ...
# ktor
c
Hey there. I’m trying to get my head around Ktor2 by creating a simple REST endpoint to manage things called ‘agents’.
Copy code
@Serializable
data class Agent(val id: Int, val hostname: String, val port: Int)
I’m struggling with handling POST:
Copy code
@Serializable
@Resource("/api/agents")
data class AgentsRoute(val sort: String? = "id") {
    @Serializable
    @Resource("{id}")
    data class Id(val parent: AgentsRoute = AgentsRoute(), val id: Int)
}

fun Application.agentRoutes() {
    val agentService = AgentService() // Talks to the database

    routing {
        get<AgentsRoute> {
            call.respond(agentService.getAll())
        }
        get<AgentsRoute.Id> { request ->
            val agent = agentService.get(request.id) ?: call.respond(
                HttpStatusCode.NotFound, "Agent not found"
            )
            call.respond(agent)
        }
        post<AgentsRoute> {
            val agent = call.receive<Agent>() // This blows up!
            // TODO
        }
        delete<AgentsRoute.Id> { request ->
            agentService.get(request.id) ?: call.respond(
                HttpStatusCode.NotFound, "Agent not found"
            )
            call.respond(agentService.delete(request.id))
        }
    }
}
I’m having a problem with the
POST
when I post some data to create a new agent:
Copy code
{
  "hostname": "192.168.1.1",
  "port": 1012
}
Here’s the exception:
Copy code
2022-04-10 16:51:06.740 [eventLoopGroupProxy-4-1] ERROR Application - Unhandled: POST - /api/agents/
kotlinx.serialization.MissingFieldException: Field 'id' is required for type with serial name 'com.sonalake.snmpsim.model.Agent', but it was missing
        at kotlinx.serialization.internal.PluginExceptionsKt.throwMissingFieldException(PluginExceptions.kt:20)
I understand why it’s happening - the JSON doesn’t contain an id property - but, as I want to create a new agent I don’t want to have to provide one. I had a look at the Ktor 2.0.0 resource-routing code snippet, but it didn’t go further than receiving the request. Any suggests on the idiomatic Ktor 2 way of doing this? Thank you 🙇
s
if the
id
property is the problem you can always declare the default value to be
-1
or something
c
Nice idea, thanks! I wondering though, if a magic number like that might be a bit of a code smell?
s
It can be.
👍 1
Another idea would be to declare separate data class without the
id
to be used when you receive POST.
c
Yeah, a guess a DTO minus the
id
would be an option.
j
Why don't you just use PUT with an id to update the agent and POST, without an id would be to create one. That is more RESTful anyway, as POST should always be creating a new item.
c
Yep, Agreed, James, but I’m trying to use Ktor Type-safe routing while avoiding having two almost identical data classes (one with an
id
, one without).
Maybe this approach is good.