Vin Norman
Vin Norman

Reputation: 3302

How to send list of files as part of a Retrofit 2 body alongside other regular string fields in Android?

as the question says, I need to send a list of files (images in my case) in a http POST request, but there are other fields alongside it (regular strings). The post looks something like this (as form data):

type: customerQuery
user: userId
message: The customer query etc.
contact_number: 01234564789
contact_email: [email protected]
files[]: list of files, as binary

I have file uploads working fine when I am only sending the files, as follows:

  @Multipart
  @POST("/exampleendpoint/{id}")
  suspend fun uploadDocument(
      @Path("id") id: String,
      @Part document: MultipartBody.Part
  ): Response<Unit>

How do I construct the retrofit interface/service to have a list of Files, and also other fields?

Thanks

Upvotes: 0

Views: 5691

Answers (2)

Vin Norman
Vin Norman

Reputation: 3302

Ok, thought I'd add my own answer for anybody using Kotlin, also this is the correct answer if you need to have your list of files/images named, like the rest of the form data. The accepted answer works if you don't need this, but in my case it didn't work as they had to be under files[].

Retrofit Service (just a simple @Body body: RequestBody field, and remove @Multipart)

@POST("exampleendpoint/{id}")
fun uploadDocuments(@Path("id") id: String, @Body body: RequestBody): Response<Unit>;

Then you need to construct a complete RequestBody including all that you need, an example as below:

val requestBody = MultipartBody.Builder().setType(MultipartBody.FORM).apply {
  addFormDataPart("type", "booking")
  addFormDataPart("user", "username")
  addFormDataPart("message", "message text goes here")
  addFormDataPart("contact_number", "0123456789")
  addFormDataPart("contact_email", "[email protected]")
  // my files are List<ByteArray>, okhttp has a few utility methods like .toRequestBody for various types like below
  files.forEachIndexed { index, bytes ->
     addFormDataPart("files[]", "$index.jpg", bytes.toRequestBody("multipart/form-data".toMediaTypeOrNull(), 0, bytes.size))
  }
}.build()
service.uploadDocuments("uploadId", requestBody)

Upvotes: 4

Priyanka
Priyanka

Reputation: 3699

do it

@Multipart
@POST("exampleendpoint/{id}")
Call<Unit> uploadDocument(@Path("id") String id,
                          @Part("type") RequestBody type,
                          @Part("user") RequestBody user,
                          @Part("message") RequestBody message,
                          @Part("contact_number") RequestBody contact_number,
                          @Part("contact_email") RequestBody contact_email,
                          @Part List<MultipartBody.Part> file);

and add list of files like this

ArrayList<File> tempFilesList = new ArrayList<>();
ArrayList<MultipartBody.Part> images = new ArrayList<>();
for (int i = 0; i < tempFilesList.size(); i++) {
    images.add(prepareImageFilePart("files" + (i + 1), tempFilesList.get(i).getImage()));
}

@NonNull
private MultipartBody.Part prepareImageFilePart(String partName, File file) {
    RequestBody requestFile =
            RequestBody.create(
                    MediaType.parse("image/jpg"),
                    file
            );
    return MultipartBody.Part.createFormData(partName, file.getName(), requestFile);
}

you can create RequestBody of other fields like this

RequestBody type = RequestBody.create(MediaType.parse("text/plain"), "your data...");

Upvotes: 3

Related Questions