kotlinkotlin-coroutinesktorkotlin-jsktor-client

Using async func in Compose Web


I should use Ktor client in Compose Web. But, It can't be called in Compose Web due to async/non-async problem. Environment is template project made by IntelliJ IDEA.

First, I use this:

val client=HttpClient(Js){
    install(ContentNegotiation){
        json()
    }
}


suspend fun shorterCall(url:String):String{
    val response = client.get(SERVER_NAME) {
        contentType(ContentType.Application.Json)
        parameter("url", url)
    }
    return response.bodyAsText()
}

suspend fun main() {
    var i by mutableStateOf("")

    renderComposable(rootElementId = "root") {
        Div({ style {
            height(100.vh)
            margin(0.px)
            width(100.vw)
        } }) {
            Input(type = InputType.Url) {
                onInput {
                    val input=it.value.trim()
                    if(input.startsWith("http"))
                        i=shorterCall(input)
                    else
                        i="NaN"
                }
            }
            Text(i)
        }
    }
}

Then, I got that error:

Suspend function can be called only within a coroutine body.

So, I tried another one:

import kotlinx.coroutines.*

fun shorterCall(url:String):String{
    var ret:String
    suspend fun t():String {
        val response = client.get(SERVER_NAME) {
            contentType(ContentType.Application.Json)
            parameter("url", url)
        }
        return response.bodyAsText()
    }
    runBlocking{
        ret=t()
    }
    return ret
}


//main func is same as upper one.

Then, I got that error:

Unresolved reference: runBlocking

+editing body 1: When I use GlobalScope.launch or js("JSCode"), It raise that error:

e: Could not find "kotlin" in [/home/user/.local/share/kotlin/daemon]
e: java.lang.IllegalStateException: FATAL ERROR: Could not find "kotlin" in [/home/user/.local/share/kotlin/daemon]

(a lot of internal errors bellow)

Solution

  • You can use the GlobalScope.launch() method to launch a job for a request in a browser environment:

    import androidx.compose.runtime.mutableStateOf
    import androidx.compose.runtime.getValue
    import androidx.compose.runtime.setValue
    import io.ktor.client.*
    import io.ktor.client.engine.js.*
    import io.ktor.client.request.*
    import io.ktor.client.statement.*
    import io.ktor.http.*
    import kotlinx.coroutines.GlobalScope
    import kotlinx.coroutines.launch
    import org.jetbrains.compose.web.attributes.InputType
    import org.jetbrains.compose.web.css.*
    import org.jetbrains.compose.web.dom.*
    import org.jetbrains.compose.web.renderComposable
    
    fun main() {
        val client = HttpClient(Js) {}
        var i by mutableStateOf("")
    
        renderComposable(rootElementId = "root") {
            Div({
                style {
                    height(100.vh)
                    margin(0.px)
                    width(100.vw)
                }
            }) {
                Input(type = InputType.Url) {
                    onInput {
                        val input = it.value.trim()
    
                        if (input.startsWith("http")) {
                            GlobalScope.launch {
                                i = client.shorterCall(input)
                            }
                        } else {
                            i = "NaN"
                        }
                    }
                }
                Text(i)
            }
        }
    }
    
    suspend fun HttpClient.shorterCall(url: String): String {
        val response = get(url) {
            contentType(ContentType.Application.Json)
        }
        return response.bodyAsText()
    }