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();
     }

 }
TestBest
  • 915
  • 5
  • 12
  • 22

2 Answers2

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.

Delyan
  • 8,881
  • 4
  • 37
  • 42
  • I have updated my question with GsonRequest. I don't know where to put the JSON string in this request. – TestBest Aug 02 '13 at 23:54
  • 4
    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`) – Delyan Aug 02 '13 at 23:58
  • I've posted how put is invoked in javascript apiary.io – TestBest Aug 03 '13 at 00:02
  • would the serialized object need to be encoded in some way or just return the json string as a byte array? – TestBest Aug 03 '13 at 00:37
  • Ok. i've updated post with potential fix. but does the json body need to be encoded like params do? – TestBest Aug 03 '13 at 00:45
  • I'm reasonably sure the format specifies its encoding as UTF-8. It definitely should not be URL encoded like params! – Delyan Aug 03 '13 at 00:50
  • 1
    Please update your main answer with suggestion for getBody(), getBodyContentType(). – TestBest Aug 03 '13 at 00:51
  • 1
    Thanks @Delyan - 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. – TheIcemanCometh May 27 '14 at 12:44
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();
            }
        }
Kutu
  • 161
  • 1
  • 8