javakotlinnetworkingktorktor-client

ktor upload file based on curl example


I have following example which works well using curl:

curl -X 'POST' \
  'https://example.com/rest/someservice?oauth_token=<token>' \
  -H 'accept: application/json' \
  -H 'Content-Type: multipart/form-data' \
  -F 'file=@docs_recognize_ok.jpg;type=image/jpeg' \
  -F 'meta={
  "images": [
    {
      "name": "file"
    }
  ]
}'

Can't figure out how to handle it using ktor client in Java/Kotlin?

For the moment I'm trying to handle it as:

        val json = "{\n" +
                "  \"images\": [\n" +
                "    {\n" +
                "      \"name\": \"file\"\n" +
                "    }\n" +
                "  ]\n" +
                "}"
        val filesList = mutableListOf<PartData>()
        val partData = formData {
            append(key = "meta", value = json, headers = Headers.build {
                append(HttpHeaders.ContentType, "application/json; charset=utf-8")
            })
            request.images.forEach { file ->
                append(
                    "file",
                    InputProvider { File(file.imageFileName).inputStream().asInput() },
                    Headers.build {
                        append(HttpHeaders.ContentType, "image/jpeg")
                    }
                )
            }
        }
        filesList.addAll(partData)
        httpClient.post("rest/someservice") {
            setBody(MultiPartFormDataContent(parts = filesList))
            parameters {
                append("oauth_token", apiKey)
            }
        }

Any ideas?


Solution

  • The information about sending multipart/form-data requests with the Ktor client can be found in the documentation. Here is a more or less direct translation of your curl command:

    val client = HttpClient(CIO)
    
    client.post("https://example.com/rest/someservice?oauth_token=<token>") {
        header(HttpHeaders.Accept, "application/json")
        setBody(
            MultiPartFormDataContent(
                formData {
                    append(
                        "meta", """{
                          "images": [
                            {
                              "name": "file"
                            }
                          ]
                        }""".trimIndent()
                    )
                    append("file", File("docs_recognize_ok.jpg").readBytes(), Headers.build {
                        append(HttpHeaders.ContentType, "image/jpeg")
                        append(HttpHeaders.ContentDisposition, "filename=\"docs_recognize_ok.jpg\"")
                    })
                },
            )
        )
    }