how to execute PUT request in Android Volley?
Asked Answered
C

2

7

I am currently using GsonRequest to issue rest GET requests. Not clear on what to use for PUT requests where I need to send over a whole JSon object to be updated. The Request object will accept PUT but I'm not sure how place the JSon object that is expected.

Here is my json to be PUT:

 {
   prop1 : true,
   prop2 : false,
   prop4 : true
 }

Here is how its submitted in apiary.io for example:

  var xhr = new XMLHttpRequest();
  xhr.open('PUT', 'http://my.apiary.io/v1/records/{myid}.json');

    xhr.send("{\n    \"isEditable\": false,\n    \"isClosed\": true,\n        \"isAvail\": true\n}");

I don't know where to put the JSON.

Thanks

public class GsonRequest<T> extends Request<T> {

private final Gson gson ;
private final Class<T> clazz;
private final Map<String, String> headers;
private final Listener<T> listener;

public GsonRequest(int method, String url, Class<T> clazz, Map<String, String> headers,
        Listener<T> listener, ErrorListener errorListener) {
    super(method, url, errorListener);

    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.registerTypeAdapter(Timestamp.class, new TimestampDeserializer());
    this.gson = gsonBuilder.create();
    this.clazz = clazz;
    this.headers = headers;
    this.listener = listener;
}

@Override
public Map<String, String> getHeaders() throws AuthFailureError {
    return headers != null ? headers : super.getHeaders();
}

@Override
protected void deliverResponse(T response) {
    listener.onResponse(response);
}

@Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
    try {
        String json = new String(
                response.data, HttpHeaderParser.parseCharset(response.headers));
        return Response.success(
                gson.fromJson(json, clazz), HttpHeaderParser.parseCacheHeaders(response));
    } catch (UnsupportedEncodingException e) {
        return Response.error(new ParseError(e));
    } catch (JsonSyntaxException e) {
        return Response.error(new ParseError(e));
    }
   }
}

And here are the base getBody methods inside the request. It seems to handle parameters on the Method.PUT, but what if its a JSON string that needs to be sent in the body?

/**
 * Returns the raw POST or PUT body to be sent.
 *
 * @throws AuthFailureError in the event of auth failure
 */
public byte[] getBody() throws AuthFailureError {
    Map<String, String> params = getParams();
    if (params != null && params.size() > 0) {
        return encodeParameters(params, getParamsEncoding());
    }
    return null;
}

/**
 * Converts <code>params</code> into an application/x-www-form-urlencoded encoded string.
 */
private byte[] encodeParameters(Map<String, String> params, String paramsEncoding) {
    StringBuilder encodedParams = new StringBuilder();
    try {
        for (Map.Entry<String, String> entry : params.entrySet()) {
            encodedParams.append(URLEncoder.encode(entry.getKey(), paramsEncoding));
            encodedParams.append('=');
            encodedParams.append(URLEncoder.encode(entry.getValue(), paramsEncoding));
            encodedParams.append('&');
        }
        return encodedParams.toString().getBytes(paramsEncoding);
    } catch (UnsupportedEncodingException uee) {
        throw new RuntimeException("Encoding not supported: " + paramsEncoding, uee);
    }
}

Suggested solution:

     // add a Json body.
    public String jsonBody;  

  /**
   * Returns the raw POST or PUT body to be sent.
   *
   * @throws AuthFailureError in the event of auth failure
   */



   public byte[] getBody() throws AuthFailureError {

     if ((getMethod() == Method.PUT) && (jsonBody != null))
     {
        return jsonBody.getBytes();  // Encoding required?????

     }
     else
     {
       return super.getBody();
     }

 }
Cynthia answered 2/8, 2013 at 23:5 Comment(0)
E
6

The abstract base class Request has a constructor which takes a Request.Method as the first parameter. All the Request implementations in volley.toolbox also have a constructor like that as well.

I'm not sure where GsonRequest is coming from but if it doesn't have a constructor which takes a Method, you can add one yourself.

Edit: You can override getBody and getBodyContentType to return the custom request body and MIME type respectively.

Elohist answered 2/8, 2013 at 23:35 Comment(8)
I have updated my question with GsonRequest. I don't know where to put the JSON string in this request.Cynthia
It seems like it doesn't support submitting data. You would need to override getBody and getBodyContentType to return the serialized object and a proper MIME type (e.g., application/json)Elohist
I've posted how put is invoked in javascript apiary.ioCynthia
would the serialized object need to be encoded in some way or just return the json string as a byte array?Cynthia
Ok. i've updated post with potential fix. but does the json body need to be encoded like params do?Cynthia
I'm reasonably sure the format specifies its encoding as UTF-8. It definitely should not be URL encoded like params!Elohist
Please update your main answer with suggestion for getBody(), getBodyContentType().Cynthia
Thanks @Elohist - overriding the getBodyContentType() method was what got me fixed. I spent WAY too much time trying to get this resolved before seeing that. I agree that the answer should be updated to include it.Hutch
P
0

I know this is a quite old topic but i had to adapt the suggested solution to make it work for me, so i though the same approach could work for others:

I had to add some headers to the getHeaders function:

        /**
         * Passing some request headers
         * */
        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            HashMap<String, String> headers = new HashMap<String, String>();
            headers.put("Content-Type", "application/json");
            headers.put("Accept", "*/*");
            return headers;
        }

Then i was able to use the suggested solution with getBody()

@Override
        /**
         * Returns the raw POST or PUT body to be sent.
         *
         * @throws AuthFailureError in the event of auth failure
         */
        public byte[] getBody() throws AuthFailureError {
            String jsonBody = "{\"status\":\"true"}";

            if ((getMethod() == Method.PUT) && (jsonBody != null)){
                return jsonBody.getBytes();
            }else{
                return super.getBody();
            }
        }
Prenotion answered 27/4, 2021 at 8:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.