简体   繁体   中英

Retrofit post data with nested request params

Currently I am working with retrofit. I am aware with post data with custom object and normal and multi form data. But i am stuck because i want to post data to server with nested request parameters.

For eg,

devicetype": "simulator",
"deviceid": "6ea09052e5b1fd10",
"appversion": "0.1",
"apiversion": "0.1",

Which i can post as a RequestBody string because i want post data with images using multiform data. So i have cleared this concept.

But now i have another custom data.

  "sitedetail": {
    "id": "1",
    "name": "xxx",
    "visitorid": "1"
},

So how can i pass this as a request params. Do need to pass a @Body which we pass as a custom data or json data normally. I stuck here.

Update

{
"devicetype": "simulator",
"deviceid": "6ea09052e5b1fd10",
"appversion": "0.1",
"apiversion": "0.1",
"timezone": "Asia/Kolkata",
"modeltype": "MI A1",
"deviceos": "9.0",
"userdeviceid": "1",
"visitorid": "1",
"siteid": "1",
"visitordetail": {
    "id": "1",
    "userid": "2",
    "name": "xxx",
    "email": "xxx@xxx.in",
    "mobile": "xxxxxxxxx",
    "dealername": "xxx"
},
"sitedetail": {
    "id": "1",
    "name": "xxx",
    "visitorid": "1"
},
"selections": [
    {
        "id": "1",
        "visitorid": "1",
        "siteid": "1",
        "designno": "xxx",
        "qty": "3",
        "roomtype": "xxx",
        "remarks": "xxx"
    },
    {
        "id": "0",
        "visitorid": "1",
        "siteid": "1",
        "designno": "xxx",
        "qty": "3",
        "roomtype": "xxx",
        "remarks": "xxx"
    }
]}

Advanced help would be appreciated!

I think you should send the json as a request body. To do so you need to generate a pojo of the corresponding json. Lets call it, ReqBody then,

// Add header items if required
@POST("endpoint")
Call<ResBody> getData(@Body ReqBody body);

Also, add .addConverterFactory(GsonConverterFactory.create()) to your Retrofit.Builder() .

Finally I resolved the issue.

If anyone want to upload image to server with extra additional parameters to server. Following are the way.

First create method in your retrofit API request interface.

@Multipart
@POST("test/test.post.json")
Call<APIResponseSiteDetails> addImages(@PartMap Map<String, RequestBody> params);

Now you have to call this method in your activity or fragment class where you want to call.

 Map<String, RequestBody> params = new HashMap<>();

if (imageData != null && imageData.size() > 0) {

                        for (int i = 0; i < imageData.size(); i++) {
                            String key = "images[" + i + "]";
                            File file = new File(imageData.get(i).getImageurl());
                            try {
                                File compressedImages = new ImageZipper(AddDetailsActivity.this).compressToFile(file);
                                params.put("" + key + "\"; filename=\"" + file.getName(), getRequestFile(compressedImages));

                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
}

above snippet code is only for sending image using MultiPart . Now if you want to send additional params with it. Then simply use this.

params.put("devicetype", toRequestBody(Constants.DEVICE_TYPE)); // This is String request body.

Now if you have another custom request using key pair value and want to send single item then you have to crate this way.

public Map<String, RequestBody> getAnotherRequest() {
    Map<String, RequestBody> paStringRequestBodyMap = new HashMap<>();
    paStringRequestBodyMap.put("userid", Functions.toRequestBody("1"));
    paStringRequestBodyMap.put("id", Functions.toRequestBody("1"));
    return paStringRequestBodyMap;
}

Now you have to add it in main request body then you have to perform.

 for (Map.Entry<String, RequestBody> entry : getAnotherRequest().entrySet()) {
                        String key = entry.getKey();
                        RequestBody value = entry.getValue();
                        params.put("details[" + key + "]", value);
 }

Now, if you want to send multiple requests, then you need to perform below code,

public Map<String, Map> getContacts() {

    Map<String, Map> paStringRequestBodyMap = new HashMap<>();

    if (showRoomDataList != null && showRoomDataList.size() > 0) {

        for (int i = 0; i < showRoomDataList.size(); i++) {

            Map<String, RequestBody> innnerList = new HashMap<>();
            innnerList.put("id", Functions.toRequestBody("0"));
            innnerList.put("visitorid", Functions.toRequestBody("0"));
            innnerList.put("siteid", Functions.toRequestBody("0"));

            innnerList.put("typeid", Functions.toRequestBody(showRoomDataList.get(i).getTypeid()));
            paStringRequestBodyMap.put(i + "", innnerList);
        }
    }
    return paStringRequestBodyMap;
}

Now put it to main request,

for (Map.Entry<String, Map> entry : getContacts().entrySet()) {

                        String key = entry.getKey();
                        Map value = entry.getValue();

                        Iterator it = value.entrySet().iterator();
                        while (it.hasNext()) {
                            Map.Entry pair = (Map.Entry) it.next();

                            RequestBody requestBody = (RequestBody) pair.getValue();

                            params.put("contacts[" + key + "]" + "[" + pair.getKey() + "]", requestBody);

                            it.remove(); // avoids a ConcurrentModificationException
                        }

                    }

For image multipart request body

private RequestBody getRequestFile(File file) {

    RequestBody fbody = RequestBody.create(MediaType.parse("image/*"), file);
    return fbody;

}

For String value request body

  public static RequestBody toRequestBody(String value) {
  RequestBody body = RequestBody.create(MediaType.parse("text/plain"), value);
  return body;
}

So above are the code to perform with single, multiple post request using key pair value with image(Multipart) data. I hope this will help to all of you.

I think that you have the same problem I had few days ago. You can find the whole topic here to see my example: Is it possible to POST a package of json objects?

You have to do something like this:

public interface API {

  @POST("YOUR_ENDPOINT")
  Call<Post> createPost(@Body PostRequest post);
}

And create this class:

public class PostRequest {
  final Param1Type param1name;
  final Param2Type param2name; 

  PostRequest(Param1Type param1name, Param2Type param2name) {
    this.param1name= param1name;
    this.param2name= param2name;
  }
}

You can try this, at first you need create a class for the 1st part of the request. So i would create something like this ->

class Article(
    @field:Json(name = "devicetype") var devicetype: String,
    @field:Json(name = "deviceid") var deviceid: String,
    @field:Json(name = "appversion") var appversion: String,
    @field:Json(name = "apiversion") var apiversion: String,
    @field:Json(name = "timezone") var timezone: String,
    @field:Json(name = "modeltype") var modeltype: String,
    @field:Json(name = "deviceos") var deviceos: String,
    @field:Json(name = "userdeviceid") var userdeviceid: String,
    @field:Json(name = "visitorid") var visitorid: String,
    @field:Json(name = "siteid") var siteid: String,
    @field:Json(name = "visitordetail") var visitordetail: List<VisitorDetail>    //Call the visitordetail class over here like this
) : Serializable

Then create a class file for "visitordetail", like this ->

class VisitorDetail(
    @field:Json(name = "id") var id: String,
    @field:Json(name = "userid") var userid: String,
    @field:Json(name = "name") var name: String,
    @field:Json(name = "email") var email: String,
    @field:Json(name = "mobile") var mobile: String,
    @field:Json(name = "dealername") var dealername: String,
    @field:Json(name = "sitedetail") var sitedetail: List<SiteDetail>    //Call the site details class over here like this
) : Serializable

Then similary create a class named "sitedetail"

class SiteDetail(
    @field:Json(name = "id") var id: String,
    @field:Json(name = "name") var name: String,
    @field:Json(name = "visitorid") var visitorid: String,
    @field:Json(name = "selections") var selections: List<Selections>    //Call the Selections class over here
): Serializable

Similarly again do the same, create a class for "selections" like this ->

class Selections(
    @field:Json(name = "id") var id: String,
    @field:Json(name = "visitorid") var visitorid: String,
    @field:Json(name = "siteid") var siteid: String,
    @field:Json(name = "designno") var designno: String,
    @field:Json(name = "qty") var qty: String,
    @field:Json(name = "roomtype") var roomtype: String,
    @field:Json(name = "remarks") var remarks: String
):Serializable

I have done this in Kotlin, but you can try it out in java to by converting it. The logic is that, you just have to convert all your responses into pojo classes wherever this is a need for calling a nesting request data. Just pass it one by one and then call the main pojo into your retrofit and rest will be handled by the library. And also you can do this for multi part too. And if there is any silly mistake like missing of comma or something then my apology for that in advance.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM