Question: if the client has a made a request that ...
# ktor
l
Question: if the client has a made a request that was redirected, can I get the server's redirection response?
Use case, am trying to get the the URL of the last request made (i.e. after all redirects) excluding 303 redirects.
Basically, trying to get example.com/bar where: 1. example.com/foo redirects to example.com/bar 2. example.com/bar redirects to exmaple.com/foobar with a 303 3. example.com/foobar redirects to example.net/foo
b
Yes, something like this should be possible with the HttpRedirect plugin
Copy code
client.monitor.subscribe(HttpResponseRedirectEvent) { response ->
   println(response.status)
}
l
Wait, http redirects are a plugin?
oh wait yeah ic
@Bruce Hamilton but how can I pass this info to the rest of my code?
Are the redirecting response's
call.attributes
copied to the request?
b
I don't think so, it would likely just be a set of the attributes of the original request that are copied, though I'm not very familiar with the code there
l
@Bruce Hamilton so
response.call.request.attributes
should work?
b
it should 🤞 😄
a
Please note that the
HttpResponseRedirectEvent
is available only in Ktor 3.. To solve the problem for Ktor 2., you can write a plugin that would add a handler for the
Send
hook to save the latest redirected location in the request attributes. Here is an example:
Copy code
val redirectKey = AttributeKey<String>("redirectKey")
val plugin = createClientPlugin("my plugin") {
    on(Send) { request ->
        val call = proceed(request)
        if (listOf(301, 302, 307, 308).contains(call.response.status.value)) {
            call.response.headers[HttpHeaders.Location]?.let { location ->
                request.attributes.put(redirectKey, location)
            }
        }
        call
    }
}

val client = HttpClient(CIO) {
    install(plugin)
}

val response = client.get("<https://httpbin.org/status/302>")
println(response.request.attributes[redirectKey])
🎉 1
l
@Aleksei Tirman [JB] I'm currently doing this:
Copy code
client.monitor.subscribe(HttpRedirect.HttpResponseRedirect) {
        if (it.status == HttpStatusCode.SeeOther && FirstSeeOtherRedirectLocation !in it.call.attributes) {
            it.call.attributes.put(FirstSeeOtherRedirectLocation, it.request.url)
        }
    }
👍 1
Ktor 2.3.9
s
Copy code
override suspend fun getNoteById(noteId: Long): NoteRow? {
    return dbQuery {
        NotesTable
            .join(
                otherTable = UserTable,
                onColumn = NotesTable.userId,
                otherColumn = UserTable.userId,
                joinType = JoinType.INNER
            )
            .select { NotesTable.noteId eq noteId }
            .singleOrNull()
            ?.let { toNoteRow(it) }
    }
}override suspend fun getUserNotes(userId: Long): Response<NoteResponse> {
        val listOfNotes = notesDao.getUserNotes(userId)
        return if (listOfNotes.isEmpty()) {
            Response.Error(
                code = HttpStatusCode.InternalServerError,
                data = NoteResponse(
                    success = false,
                    message = "No notes available, click to add notes"
                )
            )
        } else {
            Response.Success(
                data = NoteResponse(
                    success = true,
                    notes = listOfNotes.map { toNote(it) },
                    message = "Notes fetched successfully"
                )
            )
        }

    }        route("/notes"){
            delete(path = "/{noteId}") {
                try {
                    val noteId = call.getLongParameter(name = "noteId")
                    val result = repository.deleteNote(noteId = noteId)
                    call.respond(
                        status = result.code,
                        message = result.data
                    )
                } catch (badRequestError: BadRequestException) {
                    return@delete
                } catch (anyError: Throwable) {
                    call.respond(
                        status = HttpStatusCode.InternalServerError,
                        message = NoteResponse(
                            success = false,
                            message = "An unexpected error has occurred, try again!"
                        )
                    )
                }
            }
            get("/{userId}") {
                try {
                    val userId = call.parameters["userId"]!!.toLong()
                    val response = repository.getUserNotes(userId)

                    call.respond(response)
                } catch (badRequestError: BadRequestException) {
                    return@get
                } catch (anyError: Throwable) {
                    call.respond(
                        status = HttpStatusCode.InternalServerError,
                        message = NoteResponse(
                            success = false,
                            message = "An unexpected error has occurred, try again!"
                        )
                    )
                }
            }
        } please help me fix the issue i am getting the any error throwabele for the get response i have two tables a usertable and a notes table linked by userId i want to fetch all the notes created by a user
1
a
@Sajal Kumar Jana, you'd better ask this question in the #exposed channel.