2

I'm writing a WebGL app in Kotlin JS, and as such I need to fetch resource such as .obj files and shaders. I want to do this through HTTP requests, but I've run into issues.

I'm currently trying to do this via JS's fetch() API. The problem is that this is obviously asynchronous, and fetching the resources needs to be done before the render loop can start (i.e. fetching the resources is initialisation).

I'm really struggling to get this to work synchronously. That is, my program should not continue onto loading buffers and the main draw loop before it has fetched the shaders and .obj files. How can I get this to work in Kotlin JS? Is fetch() not the right way to do this?

Forumpy
  • 305
  • 1
  • 3
  • 13

3 Answers3

1

I'm not sure about fetch() but Ktor comes with a multiplatform HTTP library which you can use out of the box. You can find it here.

And example of such call looks like this:

suspend fun sequentialRequests() {
    val client = HttpClient()

    // Get the content of an URL.
    val firstBytes = client.get<ByteArray>("https://127.0.0.1:8080/a")

    // Once the previous request is done, get the content of an URL.
    val secondBytes = client.get<ByteArray>("https://127.0.0.1:8080/b")

    client.close()
}
Adam Arold
  • 29,285
  • 22
  • 112
  • 207
0

If you want to use fetch, you can do something like this.

import kotlinx.browser.window
import kotlinx.coroutines.*
import kotlin.js.Promise

    suspend fun main() {
        val promise = Promise.resolve(window.fetch("https://jsonplaceholder.typicode.com/todos/1").then {response->
            response.json()
        }.then {
            it
        }).await()
    
        console.log(JSON.stringify(promise))}

There are definitely other options. Let me know if this doesn't do it for you.

Good luck!

ruffCode
  • 271
  • 1
  • 4
0

Here is a complete framework for implementing a JSON REST API client in a browser with some examples of usage at bottom.

import kotlinx.browser.window
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.await
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import org.w3c.fetch.RequestInit
import org.w3c.fetch.Response
import kotlin.js.Promise
import kotlin.js.json

// Used throughout to wrap api calls and effects.
val mainScope = MainScope()

private suspend fun Promise<Response>.assertStatus() = await().apply {
    status.toInt().also {
        check(200 == it || 0 == it) {
            "Operation failed: $status  $url".also { msg ->
                console.log(msg)
                window.alert(msg)
            }
        }
    }
}

private suspend fun fetch(method: String, url: String, body: dynamic = null): Response =
    window.fetch(
        url, RequestInit(
            method = method,
            body = body,
            headers = json(
                "Content-Type" to "application/json",
                "Accept" to "application/json",
                "pragma" to "no-cache"
            )
        )
    ).assertStatus()

// Verbiage: expressing the semantics of each method.

private suspend fun get(url: String): Response =
    fetch("GET", url)

private suspend fun put(url: String, body: dynamic): Response =
    fetch("PUT", url, JSON.stringify(body))

private suspend fun post(url: String, body: dynamic): Response =
    fetch("POST", url, JSON.stringify(body))

private suspend fun delete(url: String): Response =
    fetch("DELETE", url)

/**
 * Serialize object from json in response.
 */
private suspend inline fun <reified T> json(response: Response): T =
    Json.decodeFromString(response.text().await())

/**
 * The API methods, mirroring the server.
 */
object API {
    private const val apiRoot = "http://localhost:8081/api"

    // Get all the records.
    suspend fun listRecords(): List<Record> =
        json(get("$apiRoot/record"))

    suspend fun deleteRecord(id: UUID) =
        delete("$apiRoot/record?id=$id")

    suspend fun updateRecord(record: Record) =
        post("$apiRoot/record", record)

    suspend fun createRecord(record: RecordWIP) =
        put("$apiRoot/record", record)
}
F. P. Freely
  • 1,026
  • 14
  • 24