Retrofit2 failed to upload image with Multipart or RequestBody

Viewed 851

I've tried couple of approaches to send image for server just like it works in Postman enter image description here

but none actually worked out.

The first way via @Multipart:

interface Api {   
@Multipart
@POST("/upload-file")
fun uploadFile(@Part("file") file: RequestBody,
               @Part("data") id: FileUploadModel): Single<Response<AdvertisementResponse>>
}

And method in repository class:

 override fun uploadFile(
    id: FileUploadModel,
    filePath: String
): Single<Response<AdvertisementResponse>> {

    val requestFile = RequestBody.create(MediaType.parse("image/*"), file)

    return api.uploadFile(requestFile, id)
}

The second way using RequestBody:

 @POST("/upload-file")
 fun uploadFile(@Body requestBody: RequestBody): Single<Response<AdvertisementResponse>>

And method in repository class:

override fun uploadFile(
    id: FileUploadModel,
    filePath: String
): Single<Response<AdvertisementResponse>> {

    val file = File(filePath)
    val builder = MultipartBody.Builder()
    builder.setType(MultipartBody.FORM)

    val requestFile = RequestBody.create(MediaType.parse("image/*"), file)

    builder.addFormDataPart("file", file.name, requestFile)
    builder.addFormDataPart("data", id.toJson())

    return api.uploadFile(builder.build())
}

The third way via MultipartBody.Part:

@Multipart
@POST("/upload-file")
fun uploadFile(@Part("file") file: MultipartBody.Part,
               @Part("data") id: FileUploadModel): Single<Response<AdvertisementResponse>>

And method in repository class:

 override fun uploadFile(
    id: FileUploadModel,
    filePath: String
): Single<Response<AdvertisementResponse>> {

    val file = File(filePath)
    val requestFile = RequestBody.create(MediaType.parse("image/*"), file)
    val multipartFile = MultipartBody.Part.createFormData("file", file.name, requestFile)

    return api.uploadFile(multipartFile, id)
}

Logs shows that the POST request for upload-file is not finished:

2020-08-15 13:52:35.828 D/OkHttpInterceptor: --> POST http://####/advertisement 2020-08-15 13:52:35.829 D/OkHttpInterceptor: Content-Type: application/json 2020-08-15 13:52:35.829 D/OkHttpInterceptor: Content-Length: 233 2020-08-15 13:52:35.829 D/OkHttpInterceptor: {"businessName":"mgskhsgmhz","email":"test@email.com","emirates":"Abu Dhabi","image":"/storage/emulated/0/Pictures/1768cbfe-e5eb-4ae0-b642-be2733cfedbe969168674235591475.jpg","note":"","ownerName":"mhzm","phone":"1111","website":""} 2020-08-15 13:52:35.829 D/OkHttpInterceptor: --> END POST (233-byte body) 2020-08-15 13:52:36.233 D/OkHttpInterceptor: <-- 201 Created http://####/advertisement (403ms) 2020-08-15 13:52:36.233 D/OkHttpInterceptor: X-Powered-By: Express 2020-08-15 13:52:36.234 D/OkHttpInterceptor: Access-Control-Allow-Origin: * 2020-08-15 13:52:36.234 D/OkHttpInterceptor: Content-Type: application/json; charset=utf-8 2020-08-15 13:52:36.234 D/OkHttpInterceptor: Content-Length: 303 2020-08-15 13:52:36.235 D/OkHttpInterceptor: ETag: W/"12f-hAPhr6BG9nzrhDMQ2eMpt2ypCAk" 2020-08-15 13:52:36.235 D/OkHttpInterceptor: Date: Sat, 15 Aug 2020 10:52:37 GMT 2020-08-15 13:52:36.235 D/OkHttpInterceptor: Connection: keep-alive 2020-08-15 13:52:36.237 D/OkHttpInterceptor: {"Error":{},"Data":{"_id":"5f37be7552e7000012180324","businessName":"mgskhsgmhz","email":"test@email.com","emirates":"Abu Dhabi","image":"/storage/emulated/0/Pictures/1768cbfe-e5eb-4ae0-b642-be2733cfedbe969168674235591475.jpg","note":"","ownerName":"mhzm","phone":"1111","website":""},"HasError":false} 2020-08-15 13:52:36.237 D/OkHttpInterceptor: <-- END HTTP (303-byte body) 2020-08-15 13:52:36.244 D/123: sent: 5f37be7552e7000012180324 2020-08-15 13:52:36.278 D/OkHttpInterceptor: --> POST http://####/upload-file 2020-08-15 13:52:36.278 D/OkHttpInterceptor: Content-Type: multipart/form-data; boundary=894cbe1b-0fc4-47c6-849d-3764193c214f 2020-08-15 13:52:36.279 D/OkHttpInterceptor: Content-Length: 104305

I wonder why Retrofit can't complete such requests.

Thanks for any suggestions

Cheers

1 Answers

The issue were caused by inability to read the file from disk.

Adding android:requestLegacyExternalStorage="true" to the Android Manifest worked for me with Android sdk 29.

<application
android:name=".MyApplication"
android:requestLegacyExternalStorage="true" ...

Apart from adding <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> permission.

Related