Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Send POST request with JSON data using Volley

I would like to send a new JsonObjectRequest request:

  • I want to receive JSON data (response from server): OK
  • I want to send JSON formatted data with this request to the server

    JsonObjectRequest request = new JsonObjectRequest(     Request.Method.POST, "myurl.com", null,     new Response.Listener<JSONObject>() {         @Override         public void onResponse(JSONObject response) {             //...         }     },     new Response.ErrorListener() {         @Override         public void onErrorResponse(VolleyError error) {             //...         }     })     {         @Override         protected Map<String,String> getParams() {             // something to do here ??             return params;         }          @Override         public Map<String, String> getHeaders() throws AuthFailureError {             // something to do here ??             return params;         }     }; 

P.S. I use GSON library in my project too.

like image 591
anthony Avatar asked Apr 22 '14 13:04

anthony


People also ask

Can we send JSON object in post request?

To post JSON to a REST API endpoint, you must send an HTTP POST request to the REST API server and provide JSON data in the body of the POST message. You also need to specify the data type in the body of the POST message using the Content-Type: application/json request header.


2 Answers

JsonObjectRequest actually accepts JSONObject as body.

From this blog article,

final String url = "some/url"; final JSONObject jsonBody = new JSONObject("{\"type\":\"example\"}");  new JsonObjectRequest(url, jsonBody, new Response.Listener<JSONObject>() { ... }); 

Here is the source code and JavaDoc (@param jsonRequest):

/**  * Creates a new request.  * @param method the HTTP method to use  * @param url URL to fetch the JSON from  * @param jsonRequest A {@link JSONObject} to post with the request. Null is allowed and  *   indicates no parameters will be posted along with request.  * @param listener Listener to receive the JSON response  * @param errorListener Error listener, or null to ignore errors.  */ public JsonObjectRequest(int method, String url, JSONObject jsonRequest,         Listener<JSONObject> listener, ErrorListener errorListener) {     super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener,                 errorListener); } 
like image 154
shkschneider Avatar answered Oct 11 '22 23:10

shkschneider


I know that this thread is quite old, but I had this problem and I came up with a cool solution which can be very useful to many because it corrects/extended the Volley library on many aspects.

I spotted some not supported-out-of-box Volley features:

  • This JSONObjectRequest is not perfect: you have to expect a JSON at the end (see the Response.Listener<JSONObject>).
  • What about Empty Responses (just with a 200 status)?
  • What do I do if I want directly my POJO from the ResponseListener?

I more or less compiled a lot of solutions in a big generic class in order to have a solution for all the problem I quoted.

  /**   * Created by laurentmeyer on 25/07/15.   */  public class GenericRequest<T> extends JsonRequest<T> {       private final Gson gson = new Gson();      private final Class<T> clazz;      private final Map<String, String> headers;      // Used for request which do not return anything from the server      private boolean muteRequest = false;       /**       * Basically, this is the constructor which is called by the others.       * It allows you to send an object of type A to the server and expect a JSON representing a object of type B.       * The problem with the #JsonObjectRequest is that you expect a JSON at the end.       * We can do better than that, we can directly receive our POJO.       * That's what this class does.       *       * @param method:        HTTP Method       * @param classtype:     Classtype to parse the JSON coming from the server       * @param url:           url to be called       * @param requestBody:   The body being sent       * @param listener:      Listener of the request       * @param errorListener: Error handler of the request       * @param headers:       Added headers       */      private GenericRequest(int method, Class<T> classtype, String url, String requestBody,                            Response.Listener<T> listener, Response.ErrorListener errorListener, Map<String, String> headers) {          super(method, url, requestBody, listener,                  errorListener);          clazz = classtype;          this.headers = headers;          configureRequest();      }       /**       * Method to be called if you want to send some objects to your server via body in JSON of the request (with headers and not muted)       *       * @param method:        HTTP Method       * @param url:           URL to be called       * @param classtype:     Classtype to parse the JSON returned from the server       * @param toBeSent:      Object which will be transformed in JSON via Gson and sent to the server       * @param listener:      Listener of the request       * @param errorListener: Error handler of the request       * @param headers:       Added headers       */      public GenericRequest(int method, String url, Class<T> classtype, Object toBeSent,                            Response.Listener<T> listener, Response.ErrorListener errorListener, Map<String, String> headers) {          this(method, classtype, url, new Gson().toJson(toBeSent), listener,                  errorListener, headers);      }       /**       * Method to be called if you want to send some objects to your server via body in JSON of the request (without header and not muted)       *       * @param method:        HTTP Method       * @param url:           URL to be called       * @param classtype:     Classtype to parse the JSON returned from the server       * @param toBeSent:      Object which will be transformed in JSON via Gson and sent to the server       * @param listener:      Listener of the request       * @param errorListener: Error handler of the request       */      public GenericRequest(int method, String url, Class<T> classtype, Object toBeSent,                            Response.Listener<T> listener, Response.ErrorListener errorListener) {          this(method, classtype, url, new Gson().toJson(toBeSent), listener,                  errorListener, new HashMap<String, String>());      }       /**       * Method to be called if you want to send something to the server but not with a JSON, just with a defined String (without header and not muted)       *       * @param method:        HTTP Method       * @param url:           URL to be called       * @param classtype:     Classtype to parse the JSON returned from the server       * @param requestBody:   String to be sent to the server       * @param listener:      Listener of the request       * @param errorListener: Error handler of the request       */      public GenericRequest(int method, String url, Class<T> classtype, String requestBody,                            Response.Listener<T> listener, Response.ErrorListener errorListener) {          this(method, classtype, url, requestBody, listener,                  errorListener, new HashMap<String, String>());      }       /**       * Method to be called if you want to GET something from the server and receive the POJO directly after the call (no JSON). (Without header)       *       * @param url:           URL to be called       * @param classtype:     Classtype to parse the JSON returned from the server       * @param listener:      Listener of the request       * @param errorListener: Error handler of the request       */      public GenericRequest(String url, Class<T> classtype, Response.Listener<T> listener, Response.ErrorListener errorListener) {          this(Request.Method.GET, url, classtype, "", listener, errorListener);      }       /**       * Method to be called if you want to GET something from the server and receive the POJO directly after the call (no JSON). (With headers)       *       * @param url:           URL to be called       * @param classtype:     Classtype to parse the JSON returned from the server       * @param listener:      Listener of the request       * @param errorListener: Error handler of the request       * @param headers:       Added headers       */      public GenericRequest(String url, Class<T> classtype, Response.Listener<T> listener, Response.ErrorListener errorListener, Map<String, String> headers) {          this(Request.Method.GET, classtype, url, "", listener, errorListener, headers);      }       /**       * Method to be called if you want to send some objects to your server via body in JSON of the request (with headers and muted)       *       * @param method:        HTTP Method       * @param url:           URL to be called       * @param classtype:     Classtype to parse the JSON returned from the server       * @param toBeSent:      Object which will be transformed in JSON via Gson and sent to the server       * @param listener:      Listener of the request       * @param errorListener: Error handler of the request       * @param headers:       Added headers       * @param mute:          Muted (put it to true, to make sense)       */      public GenericRequest(int method, String url, Class<T> classtype, Object toBeSent,                            Response.Listener<T> listener, Response.ErrorListener errorListener, Map<String, String> headers, boolean mute) {          this(method, classtype, url, new Gson().toJson(toBeSent), listener,                  errorListener, headers);          this.muteRequest = mute;      }       /**       * Method to be called if you want to send some objects to your server via body in JSON of the request (without header and muted)       *       * @param method:        HTTP Method       * @param url:           URL to be called       * @param classtype:     Classtype to parse the JSON returned from the server       * @param toBeSent:      Object which will be transformed in JSON via Gson and sent to the server       * @param listener:      Listener of the request       * @param errorListener: Error handler of the request       * @param mute:          Muted (put it to true, to make sense)       */      public GenericRequest(int method, String url, Class<T> classtype, Object toBeSent,                            Response.Listener<T> listener, Response.ErrorListener errorListener, boolean mute) {          this(method, classtype, url, new Gson().toJson(toBeSent), listener,                  errorListener, new HashMap<String, String>());          this.muteRequest = mute;       }       /**       * Method to be called if you want to send something to the server but not with a JSON, just with a defined String (without header and not muted)       *       * @param method:        HTTP Method       * @param url:           URL to be called       * @param classtype:     Classtype to parse the JSON returned from the server       * @param requestBody:   String to be sent to the server       * @param listener:      Listener of the request       * @param errorListener: Error handler of the request       * @param mute:          Muted (put it to true, to make sense)       */      public GenericRequest(int method, String url, Class<T> classtype, String requestBody,                            Response.Listener<T> listener, Response.ErrorListener errorListener, boolean mute) {          this(method, classtype, url, requestBody, listener,                  errorListener, new HashMap<String, String>());          this.muteRequest = mute;       }        @Override      protected Response<T> parseNetworkResponse(NetworkResponse response) {          // The magic of the mute request happens here          if (muteRequest) {              if (response.statusCode >= 200 && response.statusCode <= 299) {                  // If the status is correct, we return a success but with a null object, because the server didn't return anything                  return Response.success(null, HttpHeaderParser.parseCacheHeaders(response));              }          } else {              try {                  // If it's not muted; we just need to create our POJO from the returned JSON and handle correctly the errors                  String json = new String(response.data, HttpHeaderParser.parseCharset(response.headers));                  T parsedObject = gson.fromJson(json, clazz);                  return Response.success(parsedObject, HttpHeaderParser.parseCacheHeaders(response));              } catch (UnsupportedEncodingException e) {                  return Response.error(new ParseError(e));              } catch (JsonSyntaxException e) {                  return Response.error(new ParseError(e));              }          }          return null;      }       @Override      public Map<String, String> getHeaders() throws AuthFailureError {          return headers != null ? headers : super.getHeaders();      }       private void configureRequest() {          // Set retry policy          // Add headers, for auth for example          // ...      }  } 

It could seem a bit overkill but it's pretty cool to have all these constructors because you have all the cases:

(The main constructor wasn't meant to be used directly although it's, of course, possible).

  1. Request with response parsed to POJO / Headers manually set / POJO to Send
  2. Request with response parsed to POJO / POJO to Send
  3. Request with response parsed to POJO / String to Send
  4. Request with response parsed to POJO (GET)
  5. Request with response parsed to POJO (GET) / Headers manually set
  6. Request with no response (200 - Empty Body) / Headers manually set / POJO to Send
  7. Request with no response (200 - Empty Body) / POJO to Send
  8. Request with no response (200 - Empty Body) / String to Send

Of course, in order that it works, you have to have Google's GSON Lib; just add:

compile 'com.google.code.gson:gson:x.y.z' 

to your dependencies (current version is 2.3.1).

like image 38
Laurent Meyer Avatar answered Oct 11 '22 22:10

Laurent Meyer