Ktor: Different request methods with file uploading

Hello, I’m trying to upload a JSON file with a PUT method. But can’t find the proper way to do this. Is there a complete documentation? According to this, I need to use httpClient.submitFormWithBinaryData but can’t find how to change the default POST method.

Do you really need to send it as a HTML form data, not directly in PUT body? Because if you need to send it directly, then you should look at Text or Objects paragraph. It is as simple as:

client.put("<url>") {
    body = "<json>"
}

Found it could be changed this way:

fun uploadFile(url: String, filename: String, key: String = "json"): HttpResponse {
    return runBlocking {
        val headers = Headers.build {
            append(HttpHeaders.ContentType, ContentType.Application.Json)
            append(HttpHeaders.ContentDisposition, "filename=$filename")
        }

        val response: HttpResponse = httpClient.submitFormWithBinaryData(
            url = url,
            formData = formData {
                append(key, File(filename).readBytes(), headers)
            }
        ) {
            onUpload { bytesSentTotal, contentLength ->
                println("Sent $bytesSentTotal bytes from $contentLength")
            }
            method = HttpMethod.Put
        }

        println(response.readText())
        return@runBlocking response
    }
}

But not sure if it’s correct, because I still get a message: `“error” : “Invalid data; couldn’t parse JSON object, array, or value.”

Hm, I need to send it as a valid JSON file attachment.

I’m just surprised, because multipart/form-data is usually used with POST, not with PUT. While technically possible, I never heard of a service that uses PUT and multipart/form-data together.

With Python it’s only 1 string, so, I need the analog here:

request = requests.put(url, data=open(file_name, 'rb'))

And actually, it’s the Firebase API

This is exactly what I mean. This Python code does not send the data as HTML-form (multipart/form-data), but directly as a PUT body. But in Kotlin you try to send the data as HTML-form which is a totally different thing. You should do something like this:

client.put(url) {
    body = File(fileName).readText()
}
1 Like

Yeah, thanks. It’s pretty nice. Maybe official doc was confusing because it was the only sample under the uploading header and it didn’t say about HTML.

Yes, it could be confusing if you don’t know there are multiple ways of sending files through HTTP, if you aren’t familiar with what “form” or “multipart” mean in the context of HTTP. Note that the function name itself says about submitting a form, not about sending a generic request.

This is actually pretty similar in Python library you referenced above. You might accidentally try to send files with: requests.post(url, files=<files>). I think it would result in similar problems.