I am writing a telegram bot api wrapper on kotlin using ktor and came across a problem - I just can't figure out how to upload files to tda.

Tba provides 3 ways to upload files (Excerpt from documentation ):

There are three ways to send files (photos, stickers, audio, media, etc.):

  1. There is a file_id field, simply a file_id field. There are no limits for files sent this way.
  2. Provide Telegram with an HTTP URL Telegram will download and send the file. 5 MB max size for photos and 20 MB max for other types of content.
  3. Post the file using multipart / form-data in the usual way that files are uploaded via the browser. 10 MB max size for photos, 50 MB for other files.

file_id files by URL and file_id is clear and works.

Now I have such a terrible function here, makes a request to tba and parses the answer:

 suspend fun <T> makeRequest(token: String, method: TelegramMethod, vararg params: Pair<String, Any?>, files: Map<String, String> = emptyMap()): T { try { val data: List<PartData> = formData { files.forEach { key, fileName -> append(key, Files.newInputStream(Paths.get(fileName)).asInput()) } } val response = client.submitFormWithBinaryData<HttpResponse>(data) { this.method = HttpMethod.Post url { protocol = URLProtocol("https", 42) host = API_HOST encodedPath = API_PATH_PATTERN.format(token, method.methodName) params.forEach { (name, value) -> if (value != null) this.parameters[name] = value as String } } } val result = response.receive<String>() return parseTelegramAnswer<T>(response, result) } catch (e: BadResponseStatusException) { throw checkTelegramError(e) } } 

It works without files, but not with files. (I probably send the files somehow not at all correctly).
I tested on different files, here is the result:

  1. sending files weighing from 17,9 KiB and up to 56,6 KiB I received a Bad Request: wrong URL host error from the telegram Bad Request: wrong URL host
  2. sending files weighing from 75,6 KiB and up to 913,2 KiB I received an error 413 Request Entity Too

* I used the sendDocument method and sent photos

How to send files using ktor ?

  • text information is better to attach as text: a) easier to read; b) can be copied; c) the search works. To correct the text of the question, click on edit below the text of the question - aleksandr barakin
  • Thanks, @alexanderbarakin! Corrected. - Waffle Lapkin

1 answer 1

As a result, I understood how to use multipart/form-data correctly, here is the corrected function:

 internal suspend inline fun <reified T> makeRequest(token: String, method: TelegramMethod, vararg params: Pair<String, Any?>): T { try { val response = client.submitForm<HttpResponse> { this.method = HttpMethod.Post url { protocol = URLProtocol.HTTPS host = API_HOST encodedPath = API_PATH_PATTERN.format(token, method.methodName) } body = MultiPartFormDataContent( formData { params.forEach { (key, value) -> when (value) { null -> {} is MultipartFile -> append( key, value.file.inputStream().asInput(), Headers.build { append(HttpHeaders.ContentType, value.mimeType) append(HttpHeaders.ContentDisposition, "filename=${value.filename}") } ) is FileId -> append(key, value.fileId) else -> append(key, value.toString()) } } } ) } val result = response.receive<String>() val r = parseTelegramAnswer<T>(response, result) return r } catch (e: BadResponseStatusException) { val answer = mapper.readValue<TResult<T>>(e.response.content.readUTF8Line()!!) throw checkTelegramError(e.response.status, answer) } }