[kotlin] [multiplatform] [jvm-ktor] Fix formdata file upload (#21056)

* fix: kotlin multiplatform form-data file upload

* generate samples

* fix form data binary for jvm-ktor
This commit is contained in:
Julian Kalinowski 2025-04-25 10:30:25 +02:00 committed by GitHub
parent be77442bff
commit f9dedd74ec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 30 additions and 26 deletions

View File

@ -1021,7 +1021,11 @@ public class KotlinClientCodegen extends AbstractKotlinCodegen {
if ((JVM_KTOR.equals(getLibrary()) || MULTIPLATFORM.equals(getLibrary())) && operation.allParams != null) { if ((JVM_KTOR.equals(getLibrary()) || MULTIPLATFORM.equals(getLibrary())) && operation.allParams != null) {
for (CodegenParameter param : operation.allParams) { for (CodegenParameter param : operation.allParams) {
if (param.dataFormat != null && param.dataFormat.equals("binary")) { if (param.dataFormat != null && param.dataFormat.equals("binary")) {
param.baseType = param.dataType = "io.ktor.client.request.forms.InputProvider"; if (param.isContainer) {
param.baseType = param.dataType = typeMapping.get(collectionType) + "<io.ktor.client.request.forms.FormPart<io.ktor.client.request.forms.InputProvider>>";
} else {
param.baseType = param.dataType = "io.ktor.client.request.forms.FormPart<io.ktor.client.request.forms.InputProvider>";
}
} }
} }
} }

View File

@ -63,7 +63,7 @@ import com.fasterxml.jackson.databind.ObjectMapper
formData { formData {
{{#formParams}} {{#formParams}}
{{#isFile}} {{#isFile}}
{{{paramName}}}?.apply { append("{{{baseName}}}", {{{paramName}}}) } {{{paramName}}}?.apply { append({{{paramName}}}) }
{{/isFile}} {{/isFile}}
{{^isFile}} {{^isFile}}
{{^isArray}} {{^isArray}}
@ -81,7 +81,7 @@ import com.fasterxml.jackson.databind.ObjectMapper
{{/isArray}} {{/isArray}}
{{#isArray}} {{#isArray}}
for (x in {{paramName}} ?: listOf()) { for (x in {{paramName}} ?: listOf()) {
append("{{{baseName}}}", x.toString()) {{#isFile}}append(it){{/isFile}}{{^isFile}}append("{{{baseName}}}", x.toString()){{/isFile}}
} }
{{/isArray}} {{/isArray}}
{{/isFile}} {{/isFile}}

View File

@ -76,11 +76,11 @@ import kotlinx.serialization.encoding.*
{{#formParams}} {{#formParams}}
{{#isArray}} {{#isArray}}
{{{paramName}}}?.onEach { {{{paramName}}}?.onEach {
append("{{{baseName}}}[]", it) {{#isFile}}append(it){{/isFile}}{{^isFile}}append("{{{baseName}}}", it){{/isFile}}
} }
{{/isArray}} {{/isArray}}
{{^isArray}} {{^isArray}}
{{{paramName}}}?.apply { append("{{{baseName}}}", {{^isEnumOrRef}}{{{paramName}}}{{/isEnumOrRef}}{{#isEnumOrRef}}{{{paramName}}}.value{{/isEnumOrRef}}) } {{{paramName}}}?.apply { {{#isFile}}append({{{baseName}}}){{/isFile}}{{^isFile}}append("{{{baseName}}}", {{^isEnumOrRef}}{{{paramName}}}{{/isEnumOrRef}}{{#isEnumOrRef}}{{{paramName}}}.value{{/isEnumOrRef}}){{/isFile}} }
{{/isArray}} {{/isArray}}
{{/formParams}} {{/formParams}}
} }

View File

@ -90,7 +90,7 @@ open class DefaultApi : ApiClient {
fn2?.apply { append("fn2", fn2) } fn2?.apply { append("fn2", fn2) }
fn3?.apply { append("fn3", fn3) } fn3?.apply { append("fn3", fn3) }
fn4?.onEach { fn4?.onEach {
append("fn4[]", it) append("fn4", it)
} }
} }

View File

@ -360,7 +360,7 @@ uploads an image
val apiInstance = PetApi() val apiInstance = PetApi()
val petId : kotlin.Long = 789 // kotlin.Long | ID of pet to update val petId : kotlin.Long = 789 // kotlin.Long | ID of pet to update
val additionalMetadata : kotlin.String = additionalMetadata_example // kotlin.String | Additional data to pass to server val additionalMetadata : kotlin.String = additionalMetadata_example // kotlin.String | Additional data to pass to server
val file : io.ktor.client.request.forms.InputProvider = BINARY_DATA_HERE // io.ktor.client.request.forms.InputProvider | file to upload val file : io.ktor.client.request.forms.FormPart<io.ktor.client.request.forms.InputProvider> = BINARY_DATA_HERE // io.ktor.client.request.forms.FormPart<io.ktor.client.request.forms.InputProvider> | file to upload
try { try {
val result : ModelApiResponse = apiInstance.uploadFile(petId, additionalMetadata, file) val result : ModelApiResponse = apiInstance.uploadFile(petId, additionalMetadata, file)
println(result) println(result)
@ -378,7 +378,7 @@ try {
| **additionalMetadata** | **kotlin.String**| Additional data to pass to server | [optional] | | **additionalMetadata** | **kotlin.String**| Additional data to pass to server | [optional] |
| Name | Type | Description | Notes | | Name | Type | Description | Notes |
| ------------- | ------------- | ------------- | ------------- | | ------------- | ------------- | ------------- | ------------- |
| **file** | **io.ktor.client.request.forms.InputProvider**| file to upload | [optional] | | **file** | **io.ktor.client.request.forms.FormPart&lt;io.ktor.client.request.forms.InputProvider&gt;**| file to upload | [optional] |
### Return type ### Return type

View File

@ -290,14 +290,14 @@ import java.text.DateFormat
* @return ModelApiResponse * @return ModelApiResponse
*/ */
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
open suspend fun uploadFile(petId: kotlin.Long, additionalMetadata: kotlin.String?, file: io.ktor.client.request.forms.InputProvider?): HttpResponse<ModelApiResponse> { open suspend fun uploadFile(petId: kotlin.Long, additionalMetadata: kotlin.String?, file: io.ktor.client.request.forms.FormPart<io.ktor.client.request.forms.InputProvider>?): HttpResponse<ModelApiResponse> {
val localVariableAuthNames = listOf<String>("petstore_auth") val localVariableAuthNames = listOf<String>("petstore_auth")
val localVariableBody = val localVariableBody =
formData { formData {
additionalMetadata?.apply { append("additionalMetadata", additionalMetadata) } additionalMetadata?.apply { append("additionalMetadata", additionalMetadata) }
file?.apply { append("file", file) } file?.apply { append(file) }
} }
val localVariableQuery = mutableMapOf<String, List<String>>() val localVariableQuery = mutableMapOf<String, List<String>>()

View File

@ -360,7 +360,7 @@ uploads an image
val apiInstance = PetApi() val apiInstance = PetApi()
val petId : kotlin.Long = 789 // kotlin.Long | ID of pet to update val petId : kotlin.Long = 789 // kotlin.Long | ID of pet to update
val additionalMetadata : kotlin.String = additionalMetadata_example // kotlin.String | Additional data to pass to server val additionalMetadata : kotlin.String = additionalMetadata_example // kotlin.String | Additional data to pass to server
val file : io.ktor.client.request.forms.InputProvider = BINARY_DATA_HERE // io.ktor.client.request.forms.InputProvider | file to upload val file : io.ktor.client.request.forms.FormPart<io.ktor.client.request.forms.InputProvider> = BINARY_DATA_HERE // io.ktor.client.request.forms.FormPart<io.ktor.client.request.forms.InputProvider> | file to upload
try { try {
val result : ModelApiResponse = apiInstance.uploadFile(petId, additionalMetadata, file) val result : ModelApiResponse = apiInstance.uploadFile(petId, additionalMetadata, file)
println(result) println(result)
@ -378,7 +378,7 @@ try {
| **additionalMetadata** | **kotlin.String**| Additional data to pass to server | [optional] | | **additionalMetadata** | **kotlin.String**| Additional data to pass to server | [optional] |
| Name | Type | Description | Notes | | Name | Type | Description | Notes |
| ------------- | ------------- | ------------- | ------------- | | ------------- | ------------- | ------------- | ------------- |
| **file** | **io.ktor.client.request.forms.InputProvider**| file to upload | [optional] | | **file** | **io.ktor.client.request.forms.FormPart&lt;io.ktor.client.request.forms.InputProvider&gt;**| file to upload | [optional] |
### Return type ### Return type

View File

@ -288,14 +288,14 @@ import com.fasterxml.jackson.databind.ObjectMapper
* @return ModelApiResponse * @return ModelApiResponse
*/ */
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
open suspend fun uploadFile(petId: kotlin.Long, additionalMetadata: kotlin.String?, file: io.ktor.client.request.forms.InputProvider?): HttpResponse<ModelApiResponse> { open suspend fun uploadFile(petId: kotlin.Long, additionalMetadata: kotlin.String?, file: io.ktor.client.request.forms.FormPart<io.ktor.client.request.forms.InputProvider>?): HttpResponse<ModelApiResponse> {
val localVariableAuthNames = listOf<String>("petstore_auth") val localVariableAuthNames = listOf<String>("petstore_auth")
val localVariableBody = val localVariableBody =
formData { formData {
additionalMetadata?.apply { append("additionalMetadata", additionalMetadata) } additionalMetadata?.apply { append("additionalMetadata", additionalMetadata) }
file?.apply { append("file", file) } file?.apply { append(file) }
} }
val localVariableQuery = mutableMapOf<String, List<String>>() val localVariableQuery = mutableMapOf<String, List<String>>()

View File

@ -372,7 +372,7 @@ uploads an image
val apiInstance = PetApi() val apiInstance = PetApi()
val petId : kotlin.Long = 789 // kotlin.Long | ID of pet to update val petId : kotlin.Long = 789 // kotlin.Long | ID of pet to update
val additionalMetadata : kotlin.String = additionalMetadata_example // kotlin.String | Additional data to pass to server val additionalMetadata : kotlin.String = additionalMetadata_example // kotlin.String | Additional data to pass to server
val file : io.ktor.client.request.forms.InputProvider = BINARY_DATA_HERE // io.ktor.client.request.forms.InputProvider | file to upload val file : io.ktor.client.request.forms.FormPart<io.ktor.client.request.forms.InputProvider> = BINARY_DATA_HERE // io.ktor.client.request.forms.FormPart<io.ktor.client.request.forms.InputProvider> | file to upload
try { try {
val result : ModelApiResponse = apiInstance.uploadFile(petId, additionalMetadata, file) val result : ModelApiResponse = apiInstance.uploadFile(petId, additionalMetadata, file)
println(result) println(result)
@ -390,7 +390,7 @@ try {
| **additionalMetadata** | **kotlin.String**| Additional data to pass to server | [optional] | | **additionalMetadata** | **kotlin.String**| Additional data to pass to server | [optional] |
| Name | Type | Description | Notes | | Name | Type | Description | Notes |
| ------------- | ------------- | ------------- | ------------- | | ------------- | ------------- | ------------- | ------------- |
| **file** | **io.ktor.client.request.forms.InputProvider**| file to upload | [optional] | | **file** | **io.ktor.client.request.forms.FormPart&lt;io.ktor.client.request.forms.InputProvider&gt;**| file to upload | [optional] |
### Return type ### Return type

View File

@ -287,14 +287,14 @@ import io.ktor.http.ParametersBuilder
* @return ModelApiResponse * @return ModelApiResponse
*/ */
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
open suspend fun uploadFile(petId: kotlin.Long, additionalMetadata: kotlin.String?, file: io.ktor.client.request.forms.InputProvider?): HttpResponse<ModelApiResponse> { open suspend fun uploadFile(petId: kotlin.Long, additionalMetadata: kotlin.String?, file: io.ktor.client.request.forms.FormPart<io.ktor.client.request.forms.InputProvider>?): HttpResponse<ModelApiResponse> {
val localVariableAuthNames = listOf<String>("petstore_auth") val localVariableAuthNames = listOf<String>("petstore_auth")
val localVariableBody = val localVariableBody =
formData { formData {
additionalMetadata?.apply { append("additionalMetadata", additionalMetadata) } additionalMetadata?.apply { append("additionalMetadata", additionalMetadata) }
file?.apply { append("file", file) } file?.apply { append(file) }
} }
val localVariableQuery = mutableMapOf<String, List<String>>() val localVariableQuery = mutableMapOf<String, List<String>>()

View File

@ -360,7 +360,7 @@ uploads an image
val apiInstance = PetApi() val apiInstance = PetApi()
val petId : kotlin.Long = 789 // kotlin.Long | ID of pet to update val petId : kotlin.Long = 789 // kotlin.Long | ID of pet to update
val additionalMetadata : kotlin.String = additionalMetadata_example // kotlin.String | Additional data to pass to server val additionalMetadata : kotlin.String = additionalMetadata_example // kotlin.String | Additional data to pass to server
val file : io.ktor.client.request.forms.InputProvider = BINARY_DATA_HERE // io.ktor.client.request.forms.InputProvider | file to upload val file : io.ktor.client.request.forms.FormPart<io.ktor.client.request.forms.InputProvider> = BINARY_DATA_HERE // io.ktor.client.request.forms.FormPart<io.ktor.client.request.forms.InputProvider> | file to upload
try { try {
val result : ModelApiResponse = apiInstance.uploadFile(petId, additionalMetadata, file) val result : ModelApiResponse = apiInstance.uploadFile(petId, additionalMetadata, file)
println(result) println(result)
@ -378,7 +378,7 @@ try {
| **additionalMetadata** | **kotlin.String**| Additional data to pass to server | [optional] | | **additionalMetadata** | **kotlin.String**| Additional data to pass to server | [optional] |
| Name | Type | Description | Notes | | Name | Type | Description | Notes |
| ------------- | ------------- | ------------- | ------------- | | ------------- | ------------- | ------------- | ------------- |
| **file** | **io.ktor.client.request.forms.InputProvider**| file to upload | [optional] | | **file** | **io.ktor.client.request.forms.FormPart&lt;io.ktor.client.request.forms.InputProvider&gt;**| file to upload | [optional] |
### Return type ### Return type

View File

@ -324,14 +324,14 @@ open class PetApi : ApiClient {
* @return ModelApiResponse * @return ModelApiResponse
*/ */
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
open suspend fun uploadFile(petId: kotlin.Long, additionalMetadata: kotlin.String? = null, file: io.ktor.client.request.forms.InputProvider? = null): HttpResponse<ModelApiResponse> { open suspend fun uploadFile(petId: kotlin.Long, additionalMetadata: kotlin.String? = null, file: io.ktor.client.request.forms.FormPart<io.ktor.client.request.forms.InputProvider>? = null): HttpResponse<ModelApiResponse> {
val localVariableAuthNames = listOf<String>("petstore_auth") val localVariableAuthNames = listOf<String>("petstore_auth")
val localVariableBody = val localVariableBody =
formData { formData {
additionalMetadata?.apply { append("additionalMetadata", additionalMetadata) } additionalMetadata?.apply { append("additionalMetadata", additionalMetadata) }
file?.apply { append("file", file) } file?.apply { append(file) }
} }
val localVariableQuery = mutableMapOf<String, List<String>>() val localVariableQuery = mutableMapOf<String, List<String>>()

View File

@ -360,7 +360,7 @@ uploads an image
val apiInstance = PetApi() val apiInstance = PetApi()
val petId : kotlin.Long = 789 // kotlin.Long | ID of pet to update val petId : kotlin.Long = 789 // kotlin.Long | ID of pet to update
val additionalMetadata : kotlin.String = additionalMetadata_example // kotlin.String | Additional data to pass to server val additionalMetadata : kotlin.String = additionalMetadata_example // kotlin.String | Additional data to pass to server
val file : io.ktor.client.request.forms.InputProvider = BINARY_DATA_HERE // io.ktor.client.request.forms.InputProvider | file to upload val file : io.ktor.client.request.forms.FormPart<io.ktor.client.request.forms.InputProvider> = BINARY_DATA_HERE // io.ktor.client.request.forms.FormPart<io.ktor.client.request.forms.InputProvider> | file to upload
try { try {
val result : ModelApiResponse = apiInstance.uploadFile(petId, additionalMetadata, file) val result : ModelApiResponse = apiInstance.uploadFile(petId, additionalMetadata, file)
println(result) println(result)
@ -378,7 +378,7 @@ try {
| **additionalMetadata** | **kotlin.String**| Additional data to pass to server | [optional] | | **additionalMetadata** | **kotlin.String**| Additional data to pass to server | [optional] |
| Name | Type | Description | Notes | | Name | Type | Description | Notes |
| ------------- | ------------- | ------------- | ------------- | | ------------- | ------------- | ------------- | ------------- |
| **file** | **io.ktor.client.request.forms.InputProvider**| file to upload | [optional] | | **file** | **io.ktor.client.request.forms.FormPart&lt;io.ktor.client.request.forms.InputProvider&gt;**| file to upload | [optional] |
### Return type ### Return type

View File

@ -324,14 +324,14 @@ open class PetApi : ApiClient {
* @return ModelApiResponse * @return ModelApiResponse
*/ */
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
open suspend fun uploadFile(petId: kotlin.Long, additionalMetadata: kotlin.String? = null, file: io.ktor.client.request.forms.InputProvider? = null): HttpResponse<ModelApiResponse> { open suspend fun uploadFile(petId: kotlin.Long, additionalMetadata: kotlin.String? = null, file: io.ktor.client.request.forms.FormPart<io.ktor.client.request.forms.InputProvider>? = null): HttpResponse<ModelApiResponse> {
val localVariableAuthNames = listOf<String>("petstore_auth") val localVariableAuthNames = listOf<String>("petstore_auth")
val localVariableBody = val localVariableBody =
formData { formData {
additionalMetadata?.apply { append("additionalMetadata", additionalMetadata) } additionalMetadata?.apply { append("additionalMetadata", additionalMetadata) }
file?.apply { append("file", file) } file?.apply { append(file) }
} }
val localVariableQuery = mutableMapOf<String, List<String>>() val localVariableQuery = mutableMapOf<String, List<String>>()