Ktorfit icon indicating copy to clipboard operation
Ktorfit copied to clipboard

Upload a file to an S3 using a presigned URL

Open hnxtay opened this issue 4 months ago • 0 comments

Ktorfit version

1.12.0

What happened and how can we reproduce this issue?

I want to use a presigned URL to upload a file to S3. However, I am facing an error even though I have provided the URL and the request body.

Exception in thread "worker-1" java.lang.IllegalStateException: Fail to prepare request body for sending. 
The body type is: class okhttp3.RequestBody$Companion$asRequestBody$1 (Kotlin reflection is not available), with Content-Type: null.

If you expect serialized body, please check that you have installed the corresponding plugin(like `ContentNegotiation`) and set `Content-Type` header.
	at io.ktor.client.plugins.HttpSend$Plugin$install$1.invokeSuspend(HttpSend.kt:88)
	at io.ktor.client.plugins.HttpSend$Plugin$install$1.invoke(HttpSend.kt)
	at io.ktor.client.plugins.HttpSend$Plugin$install$1.invoke(HttpSend.kt)
	at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceedWith(SuspendFunctionGun.kt:88)
	at io.ktor.client.plugins.HttpCallValidator$Companion$install$1.invokeSuspend(HttpCallValidator.kt:130)
	at io.ktor.client.plugins.HttpCallValidator$Companion$install$1.invoke(HttpCallValidator.kt)
	at io.ktor.client.plugins.HttpCallValidator$Companion$install$1.invoke(HttpCallValidator.kt)
	at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78)
	at io.ktor.client.plugins.HttpRequestLifecycle$Plugin$install$1.invokeSuspend(HttpRequestLifecycle.kt:38)
	at io.ktor.client.plugins.HttpRequestLifecycle$Plugin$install$1.invoke(HttpRequestLifecycle.kt)
	at io.ktor.client.plugins.HttpRequestLifecycle$Plugin$install$1.invoke(HttpRequestLifecycle.kt)
	at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78)
	at io.ktor.util.pipeline.SuspendFunctionGun.execute$ktor_utils(SuspendFunctionGun.kt:98)
	at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:77)
	at io.ktor.client.HttpClient.execute$ktor_client_core(HttpClient.kt:191)
	at io.ktor.client.statement.HttpStatement.executeUnsafe(HttpStatement.kt:108)
	at io.ktor.client.statement.HttpStatement.execute(HttpStatement.kt:47)
	at io.ktor.client.statement.HttpStatement.execute(HttpStatement.kt:62)
	at de.jensklingenberg.ktorfit.internal.KtorfitConverterHelper.suspendRequest(KtorfitConverterHelper.kt:150)
	at data.remote.api._MediaApiImpl.uploadImageToPresignedUrl(_MediaApiImpl.kt:65)
	at data.remote.datasource.media.MediaDatasourceImpl.uploadImageToPresignedUrl(MediaDatasourceImpl.kt:25)
	at domain.repository.media.MediaRepositoryImpl.uploadImageToPresignedUrl(MediaRepositoryImpl.kt:23)
	at service.MediaUploadWorker$doWork$2.invokeSuspend(MediaUploadWorker.kt:47)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
	at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:115)
	at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:103)
	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:589)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:806)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:710)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:697)
	Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@62e9a389, java.util.concurrent.ScheduledThreadPoolExecutor@79682332[Running, pool size = 2, active threads = 1, queued tasks = 0, completed tasks = 1]]

this is my code:

@PUT
    suspend fun uploadImageToPresignedUrl(@Url url: String, @Body requestBody: RequestBody)

I attempted to include 'Content-Type: multipart/form-data' but it resulted in an error.

Exception in thread "worker-1" kotlinx.serialization.SerializationException: Serializer for class '<local class name not available>' is not found.
Please ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied.

	at kotlinx.serialization.internal.Platform_commonKt.serializerNotRegistered(Platform.common.kt:91)
	at kotlinx.serialization.SerializersKt__SerializersKt.serializer(Serializers.kt:279)
	at kotlinx.serialization.SerializersKt.serializer(Unknown Source)
	at io.ktor.serialization.kotlinx.SerializerLookupKt.guessSerializer(SerializerLookup.kt:50)
	at io.ktor.serialization.kotlinx.KotlinxSerializationConverter.serializeNullable(KotlinxSerializationConverter.kt:66)
	at io.ktor.client.plugins.contentnegotiation.ContentNegotiation.convertRequest$ktor_client_content_negotiation(ContentNegotiation.kt:180)
	at io.ktor.client.plugins.contentnegotiation.ContentNegotiation$Plugin$install$1.invokeSuspend(ContentNegotiation.kt:251)
	at io.ktor.client.plugins.contentnegotiation.ContentNegotiation$Plugin$install$1.invoke(ContentNegotiation.kt)
	at io.ktor.client.plugins.contentnegotiation.ContentNegotiation$Plugin$install$1.invoke(ContentNegotiation.kt)
	at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceedWith(SuspendFunctionGun.kt:88)
	at io.ktor.client.plugins.HttpCallValidator$Companion$install$1.invokeSuspend(HttpCallValidator.kt:130)
	at io.ktor.client.plugins.HttpCallValidator$Companion$install$1.invoke(HttpCallValidator.kt)
	at io.ktor.client.plugins.HttpCallValidator$Companion$install$1.invoke(HttpCallValidator.kt)
	at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78)
	at io.ktor.client.plugins.HttpRequestLifecycle$Plugin$install$1.invokeSuspend(HttpRequestLifecycle.kt:38)
	at io.ktor.client.plugins.HttpRequestLifecycle$Plugin$install$1.invoke(HttpRequestLifecycle.kt)
	at io.ktor.client.plugins.HttpRequestLifecycle$Plugin$install$1.invoke(HttpRequestLifecycle.kt)
	at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78)
	at io.ktor.util.pipeline.SuspendFunctionGun.execute$ktor_utils(SuspendFunctionGun.kt:98)
	at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:77)
	at io.ktor.client.HttpClient.execute$ktor_client_core(HttpClient.kt:191)
	at io.ktor.client.statement.HttpStatement.executeUnsafe(HttpStatement.kt:108)
	at io.ktor.client.statement.HttpStatement.execute(HttpStatement.kt:47)
	at io.ktor.client.statement.HttpStatement.execute(HttpStatement.kt:62)
	at de.jensklingenberg.ktorfit.internal.KtorfitConverterHelper.suspendRequest(KtorfitConverterHelper.kt:150)
	at data.remote.api._MediaApiImpl.uploadImageToPresignedUrl(_MediaApiImpl.kt:68)
	at data.remote.datasource.media.MediaDatasourceImpl.uploadImageToPresignedUrl(MediaDatasourceImpl.kt:25)
	at domain.repository.media.MediaRepositoryImpl.uploadImageToPresignedUrl(MediaRepositoryImpl.kt:23)
	at service.MediaUploadWorker$doWork$2.invokeSuspend(MediaUploadWorker.kt:47)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
	at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:115)
	at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:103)
	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:589)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:806)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:710)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:697)
	Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@142b62c2, java.util.concurrent.ScheduledThreadPoolExecutor@1d5b0f2[Running, pool size = 2, active threads = 1, queued tasks = 0, completed tasks = 1]]

What did you expect to happen?

Upload a file to an S3 using a presigned URL

Is there anything else we need to know about?

No response

hnxtay avatar Feb 23 '24 09:02 hnxtay