[Kotlin] fix #20231, OkHttp client can handle a field with a list of files (#20274)

* feat(issue-20231): Kotlin okhttp client handles correctly fields that are optional with multiple files.

* docs(issue-20231): add docstrings

* feat(issue-20231): Remove unnecessary test spec

* feat(issue-20231): Kotlin okhttp client handles correctly fields that are optional with multiple files.

* docs(issue-20231): add docstrings

* feat(issue-20231): Remove unnecessary test spec

* feat(issue-20231): Remove unnecessary if condition
This commit is contained in:
Jorge Fernandez 2024-12-09 13:00:05 +01:00 committed by GitHub
parent dc175c5335
commit a447b5988d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 1166 additions and 330 deletions

View File

@ -114,6 +114,47 @@ import com.squareup.moshi.adapter
return contentType ?: "application/octet-stream" return contentType ?: "application/octet-stream"
} }
/**
* Adds a File to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is a File
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param file The file that will be added as the field value
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, file: File) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${file.name}\"")
val fileMediaType = guessContentTypeFromFile(file).toMediaTypeOrNull()
addPart(
partHeaders.toHeaders(),
file.asRequestBody(fileMediaType)
)
}
/**
* Adds any type to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is not a File.
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param obj The field name to add in the request
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun <T> MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, obj: T?) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"")
addPart(
partHeaders.toHeaders(),
parameterToString(obj).toRequestBody(null)
)
}
protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody =
when { when {
content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull()) content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull())
@ -125,21 +166,18 @@ import com.squareup.moshi.adapter
// content's type *must* be Map<String, PartConfig<*>> // content's type *must* be Map<String, PartConfig<*>>
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
(content as Map<String, PartConfig<*>>).forEach { (name, part) -> (content as Map<String, PartConfig<*>>).forEach { (name, part) ->
if (part.body is File) { when (part.body) {
val partHeaders = part.headers.toMutableMap() + is File -> addPartToMultiPart(name, part.headers, part.body)
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${part.body.name}\"") is List<*> -> {
val fileMediaType = guessContentTypeFromFile(part.body).toMediaTypeOrNull() part.body.forEach {
addPart( if (it is File) {
partHeaders.toHeaders(), addPartToMultiPart(name, part.headers, it)
part.body.asRequestBody(fileMediaType)
)
} else { } else {
val partHeaders = part.headers.toMutableMap() + addPartToMultiPart(name, part.headers, it)
("Content-Disposition" to "form-data; name=\"$name\"") }
addPart( }
partHeaders.toHeaders(), }
parameterToString(part.body).toRequestBody(null) else -> addPartToMultiPart(name, part.headers, part.body)
)
} }
} }
}.build() }.build()

View File

@ -85,6 +85,47 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
return contentType ?: "application/octet-stream" return contentType ?: "application/octet-stream"
} }
/**
* Adds a File to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is a File
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param file The file that will be added as the field value
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, file: File) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${file.name}\"")
val fileMediaType = guessContentTypeFromFile(file).toMediaTypeOrNull()
addPart(
partHeaders.toHeaders(),
file.asRequestBody(fileMediaType)
)
}
/**
* Adds any type to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is not a File.
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param obj The field name to add in the request
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun <T> MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, obj: T?) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"")
addPart(
partHeaders.toHeaders(),
parameterToString(obj).toRequestBody(null)
)
}
protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody =
when { when {
content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull()) content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull())
@ -96,21 +137,18 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
// content's type *must* be Map<String, PartConfig<*>> // content's type *must* be Map<String, PartConfig<*>>
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
(content as Map<String, PartConfig<*>>).forEach { (name, part) -> (content as Map<String, PartConfig<*>>).forEach { (name, part) ->
if (part.body is File) { when (part.body) {
val partHeaders = part.headers.toMutableMap() + is File -> addPartToMultiPart(name, part.headers, part.body)
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${part.body.name}\"") is List<*> -> {
val fileMediaType = guessContentTypeFromFile(part.body).toMediaTypeOrNull() part.body.forEach {
addPart( if (it is File) {
partHeaders.toHeaders(), addPartToMultiPart(name, part.headers, it)
part.body.asRequestBody(fileMediaType)
)
} else { } else {
val partHeaders = part.headers.toMutableMap() + addPartToMultiPart(name, part.headers, it)
("Content-Disposition" to "form-data; name=\"$name\"") }
addPart( }
partHeaders.toHeaders(), }
parameterToString(part.body).toRequestBody(null) else -> addPartToMultiPart(name, part.headers, part.body)
)
} }
} }
}.build() }.build()

View File

@ -85,6 +85,47 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
return contentType ?: "application/octet-stream" return contentType ?: "application/octet-stream"
} }
/**
* Adds a File to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is a File
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param file The file that will be added as the field value
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, file: File) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${file.name}\"")
val fileMediaType = guessContentTypeFromFile(file).toMediaTypeOrNull()
addPart(
partHeaders.toHeaders(),
file.asRequestBody(fileMediaType)
)
}
/**
* Adds any type to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is not a File.
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param obj The field name to add in the request
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun <T> MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, obj: T?) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"")
addPart(
partHeaders.toHeaders(),
parameterToString(obj).toRequestBody(null)
)
}
protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody =
when { when {
content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull()) content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull())
@ -96,21 +137,18 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
// content's type *must* be Map<String, PartConfig<*>> // content's type *must* be Map<String, PartConfig<*>>
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
(content as Map<String, PartConfig<*>>).forEach { (name, part) -> (content as Map<String, PartConfig<*>>).forEach { (name, part) ->
if (part.body is File) { when (part.body) {
val partHeaders = part.headers.toMutableMap() + is File -> addPartToMultiPart(name, part.headers, part.body)
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${part.body.name}\"") is List<*> -> {
val fileMediaType = guessContentTypeFromFile(part.body).toMediaTypeOrNull() part.body.forEach {
addPart( if (it is File) {
partHeaders.toHeaders(), addPartToMultiPart(name, part.headers, it)
part.body.asRequestBody(fileMediaType)
)
} else { } else {
val partHeaders = part.headers.toMutableMap() + addPartToMultiPart(name, part.headers, it)
("Content-Disposition" to "form-data; name=\"$name\"") }
addPart( }
partHeaders.toHeaders(), }
parameterToString(part.body).toRequestBody(null) else -> addPartToMultiPart(name, part.headers, part.body)
)
} }
} }
}.build() }.build()

View File

@ -85,6 +85,47 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
return contentType ?: "application/octet-stream" return contentType ?: "application/octet-stream"
} }
/**
* Adds a File to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is a File
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param file The file that will be added as the field value
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, file: File) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${file.name}\"")
val fileMediaType = guessContentTypeFromFile(file).toMediaTypeOrNull()
addPart(
partHeaders.toHeaders(),
file.asRequestBody(fileMediaType)
)
}
/**
* Adds any type to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is not a File.
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param obj The field name to add in the request
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun <T> MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, obj: T?) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"")
addPart(
partHeaders.toHeaders(),
parameterToString(obj).toRequestBody(null)
)
}
protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody =
when { when {
content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull()) content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull())
@ -96,21 +137,18 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
// content's type *must* be Map<String, PartConfig<*>> // content's type *must* be Map<String, PartConfig<*>>
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
(content as Map<String, PartConfig<*>>).forEach { (name, part) -> (content as Map<String, PartConfig<*>>).forEach { (name, part) ->
if (part.body is File) { when (part.body) {
val partHeaders = part.headers.toMutableMap() + is File -> addPartToMultiPart(name, part.headers, part.body)
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${part.body.name}\"") is List<*> -> {
val fileMediaType = guessContentTypeFromFile(part.body).toMediaTypeOrNull() part.body.forEach {
addPart( if (it is File) {
partHeaders.toHeaders(), addPartToMultiPart(name, part.headers, it)
part.body.asRequestBody(fileMediaType)
)
} else { } else {
val partHeaders = part.headers.toMutableMap() + addPartToMultiPart(name, part.headers, it)
("Content-Disposition" to "form-data; name=\"$name\"") }
addPart( }
partHeaders.toHeaders(), }
parameterToString(part.body).toRequestBody(null) else -> addPartToMultiPart(name, part.headers, part.body)
)
} }
} }
}.build() }.build()

View File

@ -85,6 +85,47 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
return contentType ?: "application/octet-stream" return contentType ?: "application/octet-stream"
} }
/**
* Adds a File to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is a File
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param file The file that will be added as the field value
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, file: File) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${file.name}\"")
val fileMediaType = guessContentTypeFromFile(file).toMediaTypeOrNull()
addPart(
partHeaders.toHeaders(),
file.asRequestBody(fileMediaType)
)
}
/**
* Adds any type to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is not a File.
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param obj The field name to add in the request
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun <T> MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, obj: T?) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"")
addPart(
partHeaders.toHeaders(),
parameterToString(obj).toRequestBody(null)
)
}
protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody =
when { when {
content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull()) content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull())
@ -96,21 +137,18 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
// content's type *must* be Map<String, PartConfig<*>> // content's type *must* be Map<String, PartConfig<*>>
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
(content as Map<String, PartConfig<*>>).forEach { (name, part) -> (content as Map<String, PartConfig<*>>).forEach { (name, part) ->
if (part.body is File) { when (part.body) {
val partHeaders = part.headers.toMutableMap() + is File -> addPartToMultiPart(name, part.headers, part.body)
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${part.body.name}\"") is List<*> -> {
val fileMediaType = guessContentTypeFromFile(part.body).toMediaTypeOrNull() part.body.forEach {
addPart( if (it is File) {
partHeaders.toHeaders(), addPartToMultiPart(name, part.headers, it)
part.body.asRequestBody(fileMediaType)
)
} else { } else {
val partHeaders = part.headers.toMutableMap() + addPartToMultiPart(name, part.headers, it)
("Content-Disposition" to "form-data; name=\"$name\"") }
addPart( }
partHeaders.toHeaders(), }
parameterToString(part.body).toRequestBody(null) else -> addPartToMultiPart(name, part.headers, part.body)
)
} }
} }
}.build() }.build()

View File

@ -85,6 +85,47 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
return contentType ?: "application/octet-stream" return contentType ?: "application/octet-stream"
} }
/**
* Adds a File to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is a File
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param file The file that will be added as the field value
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, file: File) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${file.name}\"")
val fileMediaType = guessContentTypeFromFile(file).toMediaTypeOrNull()
addPart(
partHeaders.toHeaders(),
file.asRequestBody(fileMediaType)
)
}
/**
* Adds any type to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is not a File.
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param obj The field name to add in the request
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun <T> MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, obj: T?) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"")
addPart(
partHeaders.toHeaders(),
parameterToString(obj).toRequestBody(null)
)
}
protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody =
when { when {
content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull()) content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull())
@ -96,21 +137,18 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
// content's type *must* be Map<String, PartConfig<*>> // content's type *must* be Map<String, PartConfig<*>>
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
(content as Map<String, PartConfig<*>>).forEach { (name, part) -> (content as Map<String, PartConfig<*>>).forEach { (name, part) ->
if (part.body is File) { when (part.body) {
val partHeaders = part.headers.toMutableMap() + is File -> addPartToMultiPart(name, part.headers, part.body)
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${part.body.name}\"") is List<*> -> {
val fileMediaType = guessContentTypeFromFile(part.body).toMediaTypeOrNull() part.body.forEach {
addPart( if (it is File) {
partHeaders.toHeaders(), addPartToMultiPart(name, part.headers, it)
part.body.asRequestBody(fileMediaType)
)
} else { } else {
val partHeaders = part.headers.toMutableMap() + addPartToMultiPart(name, part.headers, it)
("Content-Disposition" to "form-data; name=\"$name\"") }
addPart( }
partHeaders.toHeaders(), }
parameterToString(part.body).toRequestBody(null) else -> addPartToMultiPart(name, part.headers, part.body)
)
} }
} }
}.build() }.build()

View File

@ -85,6 +85,47 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
return contentType ?: "application/octet-stream" return contentType ?: "application/octet-stream"
} }
/**
* Adds a File to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is a File
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param file The file that will be added as the field value
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, file: File) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${file.name}\"")
val fileMediaType = guessContentTypeFromFile(file).toMediaTypeOrNull()
addPart(
partHeaders.toHeaders(),
file.asRequestBody(fileMediaType)
)
}
/**
* Adds any type to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is not a File.
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param obj The field name to add in the request
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun <T> MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, obj: T?) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"")
addPart(
partHeaders.toHeaders(),
parameterToString(obj).toRequestBody(null)
)
}
protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody =
when { when {
content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull()) content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull())
@ -96,21 +137,18 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
// content's type *must* be Map<String, PartConfig<*>> // content's type *must* be Map<String, PartConfig<*>>
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
(content as Map<String, PartConfig<*>>).forEach { (name, part) -> (content as Map<String, PartConfig<*>>).forEach { (name, part) ->
if (part.body is File) { when (part.body) {
val partHeaders = part.headers.toMutableMap() + is File -> addPartToMultiPart(name, part.headers, part.body)
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${part.body.name}\"") is List<*> -> {
val fileMediaType = guessContentTypeFromFile(part.body).toMediaTypeOrNull() part.body.forEach {
addPart( if (it is File) {
partHeaders.toHeaders(), addPartToMultiPart(name, part.headers, it)
part.body.asRequestBody(fileMediaType)
)
} else { } else {
val partHeaders = part.headers.toMutableMap() + addPartToMultiPart(name, part.headers, it)
("Content-Disposition" to "form-data; name=\"$name\"") }
addPart( }
partHeaders.toHeaders(), }
parameterToString(part.body).toRequestBody(null) else -> addPartToMultiPart(name, part.headers, part.body)
)
} }
} }
}.build() }.build()

View File

@ -85,6 +85,47 @@ public open class ApiClient(public val baseUrl: String, public val client: Call.
return contentType ?: "application/octet-stream" return contentType ?: "application/octet-stream"
} }
/**
* Adds a File to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is a File
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param file The file that will be added as the field value
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, file: File) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${file.name}\"")
val fileMediaType = guessContentTypeFromFile(file).toMediaTypeOrNull()
addPart(
partHeaders.toHeaders(),
file.asRequestBody(fileMediaType)
)
}
/**
* Adds any type to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is not a File.
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param obj The field name to add in the request
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun <T> MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, obj: T?) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"")
addPart(
partHeaders.toHeaders(),
parameterToString(obj).toRequestBody(null)
)
}
protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody =
when { when {
content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull()) content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull())
@ -96,21 +137,18 @@ public open class ApiClient(public val baseUrl: String, public val client: Call.
// content's type *must* be Map<String, PartConfig<*>> // content's type *must* be Map<String, PartConfig<*>>
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
(content as Map<String, PartConfig<*>>).forEach { (name, part) -> (content as Map<String, PartConfig<*>>).forEach { (name, part) ->
if (part.body is File) { when (part.body) {
val partHeaders = part.headers.toMutableMap() + is File -> addPartToMultiPart(name, part.headers, part.body)
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${part.body.name}\"") is List<*> -> {
val fileMediaType = guessContentTypeFromFile(part.body).toMediaTypeOrNull() part.body.forEach {
addPart( if (it is File) {
partHeaders.toHeaders(), addPartToMultiPart(name, part.headers, it)
part.body.asRequestBody(fileMediaType)
)
} else { } else {
val partHeaders = part.headers.toMutableMap() + addPartToMultiPart(name, part.headers, it)
("Content-Disposition" to "form-data; name=\"$name\"") }
addPart( }
partHeaders.toHeaders(), }
parameterToString(part.body).toRequestBody(null) else -> addPartToMultiPart(name, part.headers, part.body)
)
} }
} }
}.build() }.build()

View File

@ -85,6 +85,47 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
return contentType ?: "application/octet-stream" return contentType ?: "application/octet-stream"
} }
/**
* Adds a File to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is a File
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param file The file that will be added as the field value
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, file: File) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${file.name}\"")
val fileMediaType = guessContentTypeFromFile(file).toMediaTypeOrNull()
addPart(
partHeaders.toHeaders(),
file.asRequestBody(fileMediaType)
)
}
/**
* Adds any type to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is not a File.
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param obj The field name to add in the request
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun <T> MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, obj: T?) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"")
addPart(
partHeaders.toHeaders(),
parameterToString(obj).toRequestBody(null)
)
}
protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody =
when { when {
content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull()) content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull())
@ -96,21 +137,18 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
// content's type *must* be Map<String, PartConfig<*>> // content's type *must* be Map<String, PartConfig<*>>
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
(content as Map<String, PartConfig<*>>).forEach { (name, part) -> (content as Map<String, PartConfig<*>>).forEach { (name, part) ->
if (part.body is File) { when (part.body) {
val partHeaders = part.headers.toMutableMap() + is File -> addPartToMultiPart(name, part.headers, part.body)
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${part.body.name}\"") is List<*> -> {
val fileMediaType = guessContentTypeFromFile(part.body).toMediaTypeOrNull() part.body.forEach {
addPart( if (it is File) {
partHeaders.toHeaders(), addPartToMultiPart(name, part.headers, it)
part.body.asRequestBody(fileMediaType)
)
} else { } else {
val partHeaders = part.headers.toMutableMap() + addPartToMultiPart(name, part.headers, it)
("Content-Disposition" to "form-data; name=\"$name\"") }
addPart( }
partHeaders.toHeaders(), }
parameterToString(part.body).toRequestBody(null) else -> addPartToMultiPart(name, part.headers, part.body)
)
} }
} }
}.build() }.build()

View File

@ -85,6 +85,47 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
return contentType ?: "application/octet-stream" return contentType ?: "application/octet-stream"
} }
/**
* Adds a File to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is a File
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param file The file that will be added as the field value
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, file: File) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${file.name}\"")
val fileMediaType = guessContentTypeFromFile(file).toMediaTypeOrNull()
addPart(
partHeaders.toHeaders(),
file.asRequestBody(fileMediaType)
)
}
/**
* Adds any type to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is not a File.
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param obj The field name to add in the request
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun <T> MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, obj: T?) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"")
addPart(
partHeaders.toHeaders(),
parameterToString(obj).toRequestBody(null)
)
}
protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody =
when { when {
content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull()) content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull())
@ -96,21 +137,18 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
// content's type *must* be Map<String, PartConfig<*>> // content's type *must* be Map<String, PartConfig<*>>
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
(content as Map<String, PartConfig<*>>).forEach { (name, part) -> (content as Map<String, PartConfig<*>>).forEach { (name, part) ->
if (part.body is File) { when (part.body) {
val partHeaders = part.headers.toMutableMap() + is File -> addPartToMultiPart(name, part.headers, part.body)
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${part.body.name}\"") is List<*> -> {
val fileMediaType = guessContentTypeFromFile(part.body).toMediaTypeOrNull() part.body.forEach {
addPart( if (it is File) {
partHeaders.toHeaders(), addPartToMultiPart(name, part.headers, it)
part.body.asRequestBody(fileMediaType)
)
} else { } else {
val partHeaders = part.headers.toMutableMap() + addPartToMultiPart(name, part.headers, it)
("Content-Disposition" to "form-data; name=\"$name\"") }
addPart( }
partHeaders.toHeaders(), }
parameterToString(part.body).toRequestBody(null) else -> addPartToMultiPart(name, part.headers, part.body)
)
} }
} }
}.build() }.build()

View File

@ -87,6 +87,47 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
return contentType ?: "application/octet-stream" return contentType ?: "application/octet-stream"
} }
/**
* Adds a File to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is a File
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param file The file that will be added as the field value
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, file: File) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${file.name}\"")
val fileMediaType = guessContentTypeFromFile(file).toMediaTypeOrNull()
addPart(
partHeaders.toHeaders(),
file.asRequestBody(fileMediaType)
)
}
/**
* Adds any type to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is not a File.
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param obj The field name to add in the request
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun <T> MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, obj: T?) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"")
addPart(
partHeaders.toHeaders(),
parameterToString(obj).toRequestBody(null)
)
}
protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody =
when { when {
content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull()) content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull())
@ -98,21 +139,18 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
// content's type *must* be Map<String, PartConfig<*>> // content's type *must* be Map<String, PartConfig<*>>
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
(content as Map<String, PartConfig<*>>).forEach { (name, part) -> (content as Map<String, PartConfig<*>>).forEach { (name, part) ->
if (part.body is File) { when (part.body) {
val partHeaders = part.headers.toMutableMap() + is File -> addPartToMultiPart(name, part.headers, part.body)
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${part.body.name}\"") is List<*> -> {
val fileMediaType = guessContentTypeFromFile(part.body).toMediaTypeOrNull() part.body.forEach {
addPart( if (it is File) {
partHeaders.toHeaders(), addPartToMultiPart(name, part.headers, it)
part.body.asRequestBody(fileMediaType)
)
} else { } else {
val partHeaders = part.headers.toMutableMap() + addPartToMultiPart(name, part.headers, it)
("Content-Disposition" to "form-data; name=\"$name\"") }
addPart( }
partHeaders.toHeaders(), }
parameterToString(part.body).toRequestBody(null) else -> addPartToMultiPart(name, part.headers, part.body)
)
} }
} }
}.build() }.build()

View File

@ -88,6 +88,47 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
return contentType ?: "application/octet-stream" return contentType ?: "application/octet-stream"
} }
/**
* Adds a File to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is a File
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param file The file that will be added as the field value
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, file: File) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${file.name}\"")
val fileMediaType = guessContentTypeFromFile(file).toMediaTypeOrNull()
addPart(
partHeaders.toHeaders(),
file.asRequestBody(fileMediaType)
)
}
/**
* Adds any type to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is not a File.
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param obj The field name to add in the request
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun <T> MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, obj: T?) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"")
addPart(
partHeaders.toHeaders(),
parameterToString(obj).toRequestBody(null)
)
}
protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody =
when { when {
content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull()) content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull())
@ -99,21 +140,18 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
// content's type *must* be Map<String, PartConfig<*>> // content's type *must* be Map<String, PartConfig<*>>
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
(content as Map<String, PartConfig<*>>).forEach { (name, part) -> (content as Map<String, PartConfig<*>>).forEach { (name, part) ->
if (part.body is File) { when (part.body) {
val partHeaders = part.headers.toMutableMap() + is File -> addPartToMultiPart(name, part.headers, part.body)
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${part.body.name}\"") is List<*> -> {
val fileMediaType = guessContentTypeFromFile(part.body).toMediaTypeOrNull() part.body.forEach {
addPart( if (it is File) {
partHeaders.toHeaders(), addPartToMultiPart(name, part.headers, it)
part.body.asRequestBody(fileMediaType)
)
} else { } else {
val partHeaders = part.headers.toMutableMap() + addPartToMultiPart(name, part.headers, it)
("Content-Disposition" to "form-data; name=\"$name\"") }
addPart( }
partHeaders.toHeaders(), }
parameterToString(part.body).toRequestBody(null) else -> addPartToMultiPart(name, part.headers, part.body)
)
} }
} }
}.build() }.build()

View File

@ -85,6 +85,47 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
return contentType ?: "application/octet-stream" return contentType ?: "application/octet-stream"
} }
/**
* Adds a File to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is a File
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param file The file that will be added as the field value
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, file: File) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${file.name}\"")
val fileMediaType = guessContentTypeFromFile(file).toMediaTypeOrNull()
addPart(
partHeaders.toHeaders(),
file.asRequestBody(fileMediaType)
)
}
/**
* Adds any type to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is not a File.
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param obj The field name to add in the request
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun <T> MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, obj: T?) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"")
addPart(
partHeaders.toHeaders(),
parameterToString(obj).toRequestBody(null)
)
}
protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody =
when { when {
content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull()) content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull())
@ -96,21 +137,18 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
// content's type *must* be Map<String, PartConfig<*>> // content's type *must* be Map<String, PartConfig<*>>
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
(content as Map<String, PartConfig<*>>).forEach { (name, part) -> (content as Map<String, PartConfig<*>>).forEach { (name, part) ->
if (part.body is File) { when (part.body) {
val partHeaders = part.headers.toMutableMap() + is File -> addPartToMultiPart(name, part.headers, part.body)
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${part.body.name}\"") is List<*> -> {
val fileMediaType = guessContentTypeFromFile(part.body).toMediaTypeOrNull() part.body.forEach {
addPart( if (it is File) {
partHeaders.toHeaders(), addPartToMultiPart(name, part.headers, it)
part.body.asRequestBody(fileMediaType)
)
} else { } else {
val partHeaders = part.headers.toMutableMap() + addPartToMultiPart(name, part.headers, it)
("Content-Disposition" to "form-data; name=\"$name\"") }
addPart( }
partHeaders.toHeaders(), }
parameterToString(part.body).toRequestBody(null) else -> addPartToMultiPart(name, part.headers, part.body)
)
} }
} }
}.build() }.build()

View File

@ -85,6 +85,47 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
return contentType ?: "application/octet-stream" return contentType ?: "application/octet-stream"
} }
/**
* Adds a File to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is a File
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param file The file that will be added as the field value
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, file: File) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${file.name}\"")
val fileMediaType = guessContentTypeFromFile(file).toMediaTypeOrNull()
addPart(
partHeaders.toHeaders(),
file.asRequestBody(fileMediaType)
)
}
/**
* Adds any type to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is not a File.
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param obj The field name to add in the request
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun <T> MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, obj: T?) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"")
addPart(
partHeaders.toHeaders(),
parameterToString(obj).toRequestBody(null)
)
}
protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody =
when { when {
content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull()) content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull())
@ -96,21 +137,18 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
// content's type *must* be Map<String, PartConfig<*>> // content's type *must* be Map<String, PartConfig<*>>
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
(content as Map<String, PartConfig<*>>).forEach { (name, part) -> (content as Map<String, PartConfig<*>>).forEach { (name, part) ->
if (part.body is File) { when (part.body) {
val partHeaders = part.headers.toMutableMap() + is File -> addPartToMultiPart(name, part.headers, part.body)
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${part.body.name}\"") is List<*> -> {
val fileMediaType = guessContentTypeFromFile(part.body).toMediaTypeOrNull() part.body.forEach {
addPart( if (it is File) {
partHeaders.toHeaders(), addPartToMultiPart(name, part.headers, it)
part.body.asRequestBody(fileMediaType)
)
} else { } else {
val partHeaders = part.headers.toMutableMap() + addPartToMultiPart(name, part.headers, it)
("Content-Disposition" to "form-data; name=\"$name\"") }
addPart( }
partHeaders.toHeaders(), }
parameterToString(part.body).toRequestBody(null) else -> addPartToMultiPart(name, part.headers, part.body)
)
} }
} }
}.build() }.build()

View File

@ -85,6 +85,47 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
return contentType ?: "application/octet-stream" return contentType ?: "application/octet-stream"
} }
/**
* Adds a File to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is a File
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param file The file that will be added as the field value
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, file: File) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${file.name}\"")
val fileMediaType = guessContentTypeFromFile(file).toMediaTypeOrNull()
addPart(
partHeaders.toHeaders(),
file.asRequestBody(fileMediaType)
)
}
/**
* Adds any type to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is not a File.
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param obj The field name to add in the request
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun <T> MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, obj: T?) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"")
addPart(
partHeaders.toHeaders(),
parameterToString(obj).toRequestBody(null)
)
}
protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody =
when { when {
content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull()) content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull())
@ -96,21 +137,18 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
// content's type *must* be Map<String, PartConfig<*>> // content's type *must* be Map<String, PartConfig<*>>
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
(content as Map<String, PartConfig<*>>).forEach { (name, part) -> (content as Map<String, PartConfig<*>>).forEach { (name, part) ->
if (part.body is File) { when (part.body) {
val partHeaders = part.headers.toMutableMap() + is File -> addPartToMultiPart(name, part.headers, part.body)
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${part.body.name}\"") is List<*> -> {
val fileMediaType = guessContentTypeFromFile(part.body).toMediaTypeOrNull() part.body.forEach {
addPart( if (it is File) {
partHeaders.toHeaders(), addPartToMultiPart(name, part.headers, it)
part.body.asRequestBody(fileMediaType)
)
} else { } else {
val partHeaders = part.headers.toMutableMap() + addPartToMultiPart(name, part.headers, it)
("Content-Disposition" to "form-data; name=\"$name\"") }
addPart( }
partHeaders.toHeaders(), }
parameterToString(part.body).toRequestBody(null) else -> addPartToMultiPart(name, part.headers, part.body)
)
} }
} }
}.build() }.build()

View File

@ -85,6 +85,47 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
return contentType ?: "application/octet-stream" return contentType ?: "application/octet-stream"
} }
/**
* Adds a File to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is a File
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param file The file that will be added as the field value
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, file: File) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${file.name}\"")
val fileMediaType = guessContentTypeFromFile(file).toMediaTypeOrNull()
addPart(
partHeaders.toHeaders(),
file.asRequestBody(fileMediaType)
)
}
/**
* Adds any type to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is not a File.
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param obj The field name to add in the request
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun <T> MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, obj: T?) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"")
addPart(
partHeaders.toHeaders(),
parameterToString(obj).toRequestBody(null)
)
}
protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody =
when { when {
content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull()) content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull())
@ -96,21 +137,18 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
// content's type *must* be Map<String, PartConfig<*>> // content's type *must* be Map<String, PartConfig<*>>
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
(content as Map<String, PartConfig<*>>).forEach { (name, part) -> (content as Map<String, PartConfig<*>>).forEach { (name, part) ->
if (part.body is File) { when (part.body) {
val partHeaders = part.headers.toMutableMap() + is File -> addPartToMultiPart(name, part.headers, part.body)
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${part.body.name}\"") is List<*> -> {
val fileMediaType = guessContentTypeFromFile(part.body).toMediaTypeOrNull() part.body.forEach {
addPart( if (it is File) {
partHeaders.toHeaders(), addPartToMultiPart(name, part.headers, it)
part.body.asRequestBody(fileMediaType)
)
} else { } else {
val partHeaders = part.headers.toMutableMap() + addPartToMultiPart(name, part.headers, it)
("Content-Disposition" to "form-data; name=\"$name\"") }
addPart( }
partHeaders.toHeaders(), }
parameterToString(part.body).toRequestBody(null) else -> addPartToMultiPart(name, part.headers, part.body)
)
} }
} }
}.build() }.build()

View File

@ -85,6 +85,47 @@ internal open class ApiClient(val baseUrl: String, val client: Call.Factory = de
return contentType ?: "application/octet-stream" return contentType ?: "application/octet-stream"
} }
/**
* Adds a File to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is a File
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param file The file that will be added as the field value
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, file: File) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${file.name}\"")
val fileMediaType = guessContentTypeFromFile(file).toMediaTypeOrNull()
addPart(
partHeaders.toHeaders(),
file.asRequestBody(fileMediaType)
)
}
/**
* Adds any type to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is not a File.
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param obj The field name to add in the request
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun <T> MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, obj: T?) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"")
addPart(
partHeaders.toHeaders(),
parameterToString(obj).toRequestBody(null)
)
}
protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody =
when { when {
content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull()) content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull())
@ -96,21 +137,18 @@ internal open class ApiClient(val baseUrl: String, val client: Call.Factory = de
// content's type *must* be Map<String, PartConfig<*>> // content's type *must* be Map<String, PartConfig<*>>
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
(content as Map<String, PartConfig<*>>).forEach { (name, part) -> (content as Map<String, PartConfig<*>>).forEach { (name, part) ->
if (part.body is File) { when (part.body) {
val partHeaders = part.headers.toMutableMap() + is File -> addPartToMultiPart(name, part.headers, part.body)
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${part.body.name}\"") is List<*> -> {
val fileMediaType = guessContentTypeFromFile(part.body).toMediaTypeOrNull() part.body.forEach {
addPart( if (it is File) {
partHeaders.toHeaders(), addPartToMultiPart(name, part.headers, it)
part.body.asRequestBody(fileMediaType)
)
} else { } else {
val partHeaders = part.headers.toMutableMap() + addPartToMultiPart(name, part.headers, it)
("Content-Disposition" to "form-data; name=\"$name\"") }
addPart( }
partHeaders.toHeaders(), }
parameterToString(part.body).toRequestBody(null) else -> addPartToMultiPart(name, part.headers, part.body)
)
} }
} }
}.build() }.build()

View File

@ -85,6 +85,47 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
return contentType ?: "application/octet-stream" return contentType ?: "application/octet-stream"
} }
/**
* Adds a File to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is a File
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param file The file that will be added as the field value
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, file: File) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${file.name}\"")
val fileMediaType = guessContentTypeFromFile(file).toMediaTypeOrNull()
addPart(
partHeaders.toHeaders(),
file.asRequestBody(fileMediaType)
)
}
/**
* Adds any type to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is not a File.
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param obj The field name to add in the request
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun <T> MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, obj: T?) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"")
addPart(
partHeaders.toHeaders(),
parameterToString(obj).toRequestBody(null)
)
}
protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody =
when { when {
content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull()) content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull())
@ -96,21 +137,18 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
// content's type *must* be Map<String, PartConfig<*>> // content's type *must* be Map<String, PartConfig<*>>
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
(content as Map<String, PartConfig<*>>).forEach { (name, part) -> (content as Map<String, PartConfig<*>>).forEach { (name, part) ->
if (part.body is File) { when (part.body) {
val partHeaders = part.headers.toMutableMap() + is File -> addPartToMultiPart(name, part.headers, part.body)
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${part.body.name}\"") is List<*> -> {
val fileMediaType = guessContentTypeFromFile(part.body).toMediaTypeOrNull() part.body.forEach {
addPart( if (it is File) {
partHeaders.toHeaders(), addPartToMultiPart(name, part.headers, it)
part.body.asRequestBody(fileMediaType)
)
} else { } else {
val partHeaders = part.headers.toMutableMap() + addPartToMultiPart(name, part.headers, it)
("Content-Disposition" to "form-data; name=\"$name\"") }
addPart( }
partHeaders.toHeaders(), }
parameterToString(part.body).toRequestBody(null) else -> addPartToMultiPart(name, part.headers, part.body)
)
} }
} }
}.build() }.build()

View File

@ -85,6 +85,47 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
return contentType ?: "application/octet-stream" return contentType ?: "application/octet-stream"
} }
/**
* Adds a File to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is a File
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param file The file that will be added as the field value
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, file: File) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${file.name}\"")
val fileMediaType = guessContentTypeFromFile(file).toMediaTypeOrNull()
addPart(
partHeaders.toHeaders(),
file.asRequestBody(fileMediaType)
)
}
/**
* Adds any type to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is not a File.
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param obj The field name to add in the request
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun <T> MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, obj: T?) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"")
addPart(
partHeaders.toHeaders(),
parameterToString(obj).toRequestBody(null)
)
}
protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody =
when { when {
content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull()) content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull())
@ -96,21 +137,18 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
// content's type *must* be Map<String, PartConfig<*>> // content's type *must* be Map<String, PartConfig<*>>
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
(content as Map<String, PartConfig<*>>).forEach { (name, part) -> (content as Map<String, PartConfig<*>>).forEach { (name, part) ->
if (part.body is File) { when (part.body) {
val partHeaders = part.headers.toMutableMap() + is File -> addPartToMultiPart(name, part.headers, part.body)
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${part.body.name}\"") is List<*> -> {
val fileMediaType = guessContentTypeFromFile(part.body).toMediaTypeOrNull() part.body.forEach {
addPart( if (it is File) {
partHeaders.toHeaders(), addPartToMultiPart(name, part.headers, it)
part.body.asRequestBody(fileMediaType)
)
} else { } else {
val partHeaders = part.headers.toMutableMap() + addPartToMultiPart(name, part.headers, it)
("Content-Disposition" to "form-data; name=\"$name\"") }
addPart( }
partHeaders.toHeaders(), }
parameterToString(part.body).toRequestBody(null) else -> addPartToMultiPart(name, part.headers, part.body)
)
} }
} }
}.build() }.build()

View File

@ -85,6 +85,47 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
return contentType ?: "application/octet-stream" return contentType ?: "application/octet-stream"
} }
/**
* Adds a File to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is a File
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param file The file that will be added as the field value
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, file: File) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${file.name}\"")
val fileMediaType = guessContentTypeFromFile(file).toMediaTypeOrNull()
addPart(
partHeaders.toHeaders(),
file.asRequestBody(fileMediaType)
)
}
/**
* Adds any type to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is not a File.
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param obj The field name to add in the request
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun <T> MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, obj: T?) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"")
addPart(
partHeaders.toHeaders(),
parameterToString(obj).toRequestBody(null)
)
}
protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody =
when { when {
content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull()) content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull())
@ -96,21 +137,18 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
// content's type *must* be Map<String, PartConfig<*>> // content's type *must* be Map<String, PartConfig<*>>
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
(content as Map<String, PartConfig<*>>).forEach { (name, part) -> (content as Map<String, PartConfig<*>>).forEach { (name, part) ->
if (part.body is File) { when (part.body) {
val partHeaders = part.headers.toMutableMap() + is File -> addPartToMultiPart(name, part.headers, part.body)
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${part.body.name}\"") is List<*> -> {
val fileMediaType = guessContentTypeFromFile(part.body).toMediaTypeOrNull() part.body.forEach {
addPart( if (it is File) {
partHeaders.toHeaders(), addPartToMultiPart(name, part.headers, it)
part.body.asRequestBody(fileMediaType)
)
} else { } else {
val partHeaders = part.headers.toMutableMap() + addPartToMultiPart(name, part.headers, it)
("Content-Disposition" to "form-data; name=\"$name\"") }
addPart( }
partHeaders.toHeaders(), }
parameterToString(part.body).toRequestBody(null) else -> addPartToMultiPart(name, part.headers, part.body)
)
} }
} }
}.build() }.build()

View File

@ -86,6 +86,47 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
return contentType ?: "application/octet-stream" return contentType ?: "application/octet-stream"
} }
/**
* Adds a File to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is a File
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param file The file that will be added as the field value
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, file: File) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${file.name}\"")
val fileMediaType = guessContentTypeFromFile(file).toMediaTypeOrNull()
addPart(
partHeaders.toHeaders(),
file.asRequestBody(fileMediaType)
)
}
/**
* Adds any type to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is not a File.
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param obj The field name to add in the request
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun <T> MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, obj: T?) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"")
addPart(
partHeaders.toHeaders(),
parameterToString(obj).toRequestBody(null)
)
}
protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody =
when { when {
content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull()) content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull())
@ -97,21 +138,18 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
// content's type *must* be Map<String, PartConfig<*>> // content's type *must* be Map<String, PartConfig<*>>
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
(content as Map<String, PartConfig<*>>).forEach { (name, part) -> (content as Map<String, PartConfig<*>>).forEach { (name, part) ->
if (part.body is File) { when (part.body) {
val partHeaders = part.headers.toMutableMap() + is File -> addPartToMultiPart(name, part.headers, part.body)
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${part.body.name}\"") is List<*> -> {
val fileMediaType = guessContentTypeFromFile(part.body).toMediaTypeOrNull() part.body.forEach {
addPart( if (it is File) {
partHeaders.toHeaders(), addPartToMultiPart(name, part.headers, it)
part.body.asRequestBody(fileMediaType)
)
} else { } else {
val partHeaders = part.headers.toMutableMap() + addPartToMultiPart(name, part.headers, it)
("Content-Disposition" to "form-data; name=\"$name\"") }
addPart( }
partHeaders.toHeaders(), }
parameterToString(part.body).toRequestBody(null) else -> addPartToMultiPart(name, part.headers, part.body)
)
} }
} }
}.build() }.build()

View File

@ -85,6 +85,47 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
return contentType ?: "application/octet-stream" return contentType ?: "application/octet-stream"
} }
/**
* Adds a File to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is a File
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param file The file that will be added as the field value
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, file: File) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${file.name}\"")
val fileMediaType = guessContentTypeFromFile(file).toMediaTypeOrNull()
addPart(
partHeaders.toHeaders(),
file.asRequestBody(fileMediaType)
)
}
/**
* Adds any type to a MultipartBody.Builder
* Defined a helper in the requestBody method to not duplicate code
* It will be used when the content is a FormDataMediaType and the body of the PartConfig is not a File.
*
* @param name The field name to add in the request
* @param headers The headers that are in the PartConfig
* @param obj The field name to add in the request
* @return The method returns Unit but the new Part is added to the Builder that the extension function is applying on
* @see requestBody
*/
protected fun <T> MultipartBody.Builder.addPartToMultiPart(name: String, headers: Map<String, String>, obj: T?) {
val partHeaders = headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"")
addPart(
partHeaders.toHeaders(),
parameterToString(obj).toRequestBody(null)
)
}
protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody =
when { when {
content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull()) content is ByteArray -> content.toRequestBody((mediaType ?: guessContentTypeFromByteArray(content)).toMediaTypeOrNull())
@ -96,21 +137,18 @@ open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClie
// content's type *must* be Map<String, PartConfig<*>> // content's type *must* be Map<String, PartConfig<*>>
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
(content as Map<String, PartConfig<*>>).forEach { (name, part) -> (content as Map<String, PartConfig<*>>).forEach { (name, part) ->
if (part.body is File) { when (part.body) {
val partHeaders = part.headers.toMutableMap() + is File -> addPartToMultiPart(name, part.headers, part.body)
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${part.body.name}\"") is List<*> -> {
val fileMediaType = guessContentTypeFromFile(part.body).toMediaTypeOrNull() part.body.forEach {
addPart( if (it is File) {
partHeaders.toHeaders(), addPartToMultiPart(name, part.headers, it)
part.body.asRequestBody(fileMediaType)
)
} else { } else {
val partHeaders = part.headers.toMutableMap() + addPartToMultiPart(name, part.headers, it)
("Content-Disposition" to "form-data; name=\"$name\"") }
addPart( }
partHeaders.toHeaders(), }
parameterToString(part.body).toRequestBody(null) else -> addPartToMultiPart(name, part.headers, part.body)
)
} }
} }
}.build() }.build()