deserialize JSON with Ktor client

119 views Asked by At

I'm new to Kotlin and trying Ktor 3.0.0-beta-1 to build API. I managed to build a route and it's working when I access localhost:port/api/path/to/route, but I'm having trouble testing it.

According to https://ktor.io/docs/3.0.0-beta-1/serialization-client.html I should be able to create client and test the route like this:

class ApplicationTest {
    val client = HttpClient() {
        install(ContentNegotiation) {
            json()
        }
    }
    @Test
    fun testRoute() = testApplication {
        application {}
        val value: ReturnedValue = client.get("/api/path/to/route").body()
    }
}

but have error Unresolved reference: body

I also tried

    client.get("/api/path/to/route").apply {
        assertEquals(ReturnedValue(), body<ReturnedValue>())
    }

because there was an autogenerated test case

    client.get("/").apply {
        assertEquals(HttpStatusCode.OK, status)
        assertEquals("Hello World!", bodyAsText())
    }
1

There are 1 answers

0
user2590854 On

I finally got it working, thank you commenters!

import io.ktor.client.call.body
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
import io.ktor.client.request.get
import io.ktor.client.statement.bodyAsText
import io.ktor.http.HttpStatusCode
import io.ktor.serialization.kotlinx.json.json
import io.ktor.server.testing.testApplication
import kotlin.test.assertEquals
import kotlin.test.Test

class ApplicationTest {
    @Test
    fun testItem() = testApplication {
        val client = createClient {
            install(ContentNegotiation) {
                json()
            }
        }
        client.get("/api/path/to/route").apply {
            val item: ReturnedValue = body()
        }
    }
}

Since I'm new to Kotlin, it was hard to find what is and should be coming from where.

  • The import for body, which @simon-jacobs pointed out, was missing from the article. I posted the question after ChatGPT and Google didn't help me finding where to import it from.
  • Initially generated trivial testing code was like testApplication {client...}, which was using default client. Following the article, I switched to trying to create one by HttpClient, which does not apply to testing. Thanks to @aleksei-tirman, I finally understood that I have to use createClient and that it is a dedicated way to create a client, with the context provided by testApplication (so only callable inside).
  • apply is a scope function which confused me by making methods, extension functions and normal functions indistinguishable. It makes the code shorter but does no actual work. When I read the code I have to take care of it, but no need for use by myself.