3

Using Retrofit 2.4.0, I am making a @Multipart @POST request. I am sending a file as @Part along with some metadata as@PartMap. This is what the call looks like.

@Multipart
@POST("https://8hoot.com/my-path")
Single<Response<UploadMediaResponseModel>> uploadMedia(
        @PartMap Map<String, RequestBody> metadata,
        @Part MultipartBody.Part filePart
);

There is another Map<String, String>, let us call it subMetaMap, which contains related key-value pairs.

How can I store this subMetaMap in the @PartMap metadata? Something like shown below.

RequestBody subMetaMapAsRequestBody; // Convert subMetaMap to RequestBody
metadata.put("subMeta", subMetaMapAsRequestBody);

Currently, I am using the following method.

for (String s : subMetaMap.keySet()) {
    RequestBody requestBody = RequestBody.create(MultipartBody.FORM, subMetaMap.get(s));
    metadata.put(s, requestBody);
}

This is not the desired solution as I want the whole subMetaMap as the RequestBody not its individual key-value pairs


Edit 1- The backend team doesn't take different MIME types during Multipart request. So sending JSON, MessagePack, etc. is not an option.

potatoPC
  • 67
  • 1
  • 8

2 Answers2

5

Let's assume you have following map you want to send this data to retrofit request body

HashMap<String, String> map = new HashMap<>();
map.put("key1", "value1");
map.put("key2", "value2");
map.put("key3", "value3");
map.put("key4", "value4");

Following is the URL Request method:

@FormUrlEncoded
@POST("/yourapiname")
Call<ResponseObj> methodName(@FieldMap HashMap<String, String> yourHasMapObject);

If you want to add file and hashmap then use the following method:

@Multipart
@POST("yourapiname")
Call<ResponseObj> methodName(@HeaderMap HashMap<String, String> yourHasMapObject, @Part MultipartBody.Part file);
aanshu
  • 1,602
  • 12
  • 13
  • Then I will have to do another request for the `filePart`? – potatoPC Nov 01 '18 at 14:00
  • Using `FieldMap` in `Multipart` throws an error. https://stackoverflow.com/questions/39820762/using-fieldmap-and-part-in-single-request-in-retrofit2-gets-java-lang-illegala#40136931 – potatoPC Nov 01 '18 at 14:22
  • got it, one other option is use the header and in request body send the multipart? can you go with this solution? – aanshu Nov 01 '18 at 14:28
  • 1
    Good approach. I think this might work. Just to make sure we are on the same page. You are suggesting that instead of having `subMeta` key and `subMetaMap` value pair in `@PartMap`, I should put it in the header and get it from there in the backend application. Is this right? – potatoPC Nov 01 '18 at 14:34
  • I have updated the answer, please have a look on that, I am confident it will work, I am also using this approach. – aanshu Nov 01 '18 at 14:39
  • `@HeaderMap` will work, I have another concern. A large header can cause HTTP server to drop connections. How do you deal with this? – potatoPC Nov 01 '18 at 14:42
  • Apache default limit is 8KB, in IIS its 16K for headers, do you think you will be sending more data than that? I believe 8kb data is very large in text – aanshu Nov 01 '18 at 14:47
  • I think this would be true for a map too. – potatoPC Nov 01 '18 at 14:51
  • retrofit will just convert your map into json string in key-value pair nothing else. If I am not wrong you may send upto 8k characters for apache and larger for other servers and it depends upon default setting of your server as well. – aanshu Nov 01 '18 at 14:54
  • kindly mark as answer if you found solution and it could help others. Atleas if it helped you personally please upvote it. – aanshu Nov 01 '18 at 14:56
  • 1
    True, and the map's size is barely KiBs – potatoPC Nov 01 '18 at 14:56
  • Sure. I will upvote but I think the original question is still unanswered. So, I won't accept the answer. Hope you understand and don't mind – potatoPC Nov 01 '18 at 14:58
  • No worries at all, accept it as answer if its worthy. – aanshu Nov 01 '18 at 15:11
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/182946/discussion-between-potatopc-and-kunal-mahajan). – potatoPC Nov 01 '18 at 15:16
0

You should pass the other map in the same way you are passing the first map.

First, convert the values of second map from String to RequestBody and then your request should be like follows:

@Multipart
@POST("https://8hoot.com/my-path")
Single<Response<UploadMediaResponseModel>> uploadMedia(
        @PartMap Map<String, RequestBody> metadata,
        @PartMap Map<String, RequestBody> anotherMetaData,
        @Part MultipartBody.Part filePart
);
Ankit Mehta
  • 4,251
  • 4
  • 19
  • 27