https://kotlinlang.org logo
#ktor
Title
# ktor
r

Rohan Maity

08/02/2022, 7:50 AM
hi I am trying to do a redirect like this (using
ktor-server-resources
)
Copy code
suspend fun ApplicationCall.redirect(resource: Any) {
    val path = application.href(resource)
    respondRedirect(path)
}
And here is the file where redirect is used
Copy code
const val PHRASES = "/phrases"

@Serializable
@Resource(PHRASES)
class Phrases

fun Route.phrases(db: Repository) {
    authenticate("auth") {
        get<Phrases> {
            val user = call.authentication.principal as User
            val phrases = db.phrases().toTypedArray()
            call.respond(
                FreeMarkerContent(
                    "phrases.ftl",
                    mapOf("phrases" to phrases, "displayName" to user.displayName)
                )
            )
        }

        post<Phrases> {
            val params = call.receiveParameters()
            val action = params["action"] ?: throw IllegalArgumentException("Missing parameter: action")
            when(action) {
                "delete" -> {
                    val id = params["id"] ?: throw IllegalArgumentException("Missing parameter: id")
                    db.remove(id)
                }
                "add" -> {
                    val emoji = params["emoji"] ?: throw IllegalArgumentException("Missing parameter: emoji")
                    val phrase = params["phrase"] ?: throw IllegalArgumentException("Missing parameter: phrase")
                    db.add(EmojiPhrase(emoji, phrase))
                }
            }
            call.redirect(Phrases)
        }
    }
}
Initial page loads fine But on redirect it fails on browser console I see this 405 error Now I am not sure what is wrong here Update Actually on further checking its
POST
method which is not working I am not sure what's wrong when I simply use
post(StringUrl)
it works but when
server-resources
it does not work Solved It was the issue of imports, I used the
<http://server.routing.post|server.routing.post>
instead of
<http://server.resources.post|server.resources.post>
When using
server-resources
plugin in ktor, one needs to use HTTP methods from
server.resources
package and not from
server.routing
package Thanks @Aleksei Tirman [JB] helping me here
a

Aleksei Tirman [JB]

08/02/2022, 8:09 AM
Firstly, the
kotlinx.serialization
framework cannot serialize objects of
Any
type so you need to have a refied type parameter in the
redirect
method:
Copy code
suspend inline fun <reified T: Any> ApplicationCall.redirect(resource: T) {
    val path = application.href(resource)
    respondRedirect(path)
}
Secondly, you have to instantiate your resource in the POST route to make a redirect:
Copy code
post<Phrases> {
    // ...
    call.redirect(Phrases())
}
Also, there are some problems with imports generated by IntelliJ IDEA,
r

Rohan Maity

08/02/2022, 8:10 AM
I have fixed these things But POST method errors still persists
Also, there are some problems with imports generated by IntelliJ IDEA,
Can you please explain this?
a

Aleksei Tirman [JB]

08/02/2022, 8:11 AM
Could you please share your imports (
import
statements) ?
r

Rohan Maity

08/02/2022, 8:12 AM
here is whole file
Copy code
package com.raywenderlich.webapp

import com.raywenderlich.model.EmojiPhrase
import com.raywenderlich.model.User
import com.raywenderlich.redirect
import com.raywenderlich.repository.Repository
import io.ktor.resources.*
import io.ktor.server.application.*
import io.ktor.server.auth.*
import io.ktor.server.freemarker.*
import io.ktor.server.request.*
import io.ktor.server.resources.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import <http://io.ktor.server.routing.post|io.ktor.server.routing.post>
import kotlinx.serialization.Serializable

const val PHRASES = "/phrases"

@Serializable
@Resource(PHRASES)
class Phrases

fun Route.phrases(db: Repository) {
    authenticate("auth") {
        get<Phrases> {
            val user = call.authentication.principal as User
            val phrases = db.phrases().toTypedArray()
            call.respond(
                FreeMarkerContent(
                    "phrases.ftl",
                    mapOf("phrases" to phrases, "displayName" to user.displayName)
                )
            )
        }

        post<Phrases> {
            println("Path $it")
            val params = call.receiveParameters()
            val action = params["action"] ?: throw IllegalArgumentException("Missing parameter: action")
            when(action) {
                "delete" -> {
                    val id = params["id"] ?: throw IllegalArgumentException("Missing parameter: id")
                    db.remove(id)
                }
                "add" -> {
                    val emoji = params["emoji"] ?: throw IllegalArgumentException("Missing parameter: emoji")
                    val phrase = params["phrase"] ?: throw IllegalArgumentException("Missing parameter: phrase")
                    db.add(EmojiPhrase(emoji, phrase))
                }
            }
            call.redirect(Phrases())
        }
    }
}
a

Aleksei Tirman [JB]

08/02/2022, 8:15 AM
Please replace
import <http://io.ktor.server.routing.post|io.ktor.server.routing.post>
with
import <http://io.ktor.server.resources.post|io.ktor.server.resources.post>
r

Rohan Maity

08/02/2022, 8:18 AM
It worked thanks. I was under the impression Post method of routing will handle the resources
I think I should avoid wildcard imports it confused alot TBH
👌 1
Thank you so much @Aleksei Tirman [JB]
32 Views