StringRequest with JSON body - android

I'm trying to send a request using Volley but I can't figure how to make it work.
I need to send a POST request with JSON encoded data as the body, but after hours of trying different things I still can't make it work.
This is my current code for the request:
User user = User.getUser(context);
String account = user.getUserAccount();
String degreeCode = user.getDegreeCode();
final JSONObject body = new JSONObject();
try {
body.put(NEWS_KEY, 0);
body.put(NEWS_DEGREE, degreeCode);
body.put(NEWS_COORDINATION, 0);
body.put(NEWS_DIVISION, 0);
body.put(NEWS_ACCOUNT, account);
} catch (JSONException e) {
e.printStackTrace();
}
StringRequest request = new StringRequest(Request.Method.POST, GET_NEWS, new Response.Listener<JSONObject>() {
#Override
public void onResponse(String response) {
Log.i(TAG, response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e(TAG, "Error: " + getMessage(error, context));
Toast.makeText(context, getMessage(error, context), Toast.LENGTH_SHORT).show();
}
}) {
#Override
public byte[] getBody() throws AuthFailureError {
return body.toString().getBytes();
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type","application/json");
return headers;
}
};
queue.add(request);
But this code always returns "Bad request error"
Some things I've tried:
Override getParams() method instead of getBody(). (Didn't work)
Send a JSONObjectRequest with the body on the constructor. This one worked, but because my web service returns a String value I always get a ParseError. That's why I'm using StringRequest.
Any help is very much appreciated.

As already mentioned on njzk2's comment, the easiest way is to override getBodyContentType() instead. Overriding getHeaders() could probably work too, but you need to put all necessary headers, not only Content-Type, since you basically override the headers that the original method set.
Your code should look like this:
StringRequest request = new StringRequest(...) {
#Override
public byte[] getBody() throws AuthFailureError {
return body.toString().getBytes();
}
#Override
public String getBodyContentType() {
return "application/json";
}
};

Related

Can't access volley answer saved

I am using this method to access a post Volley request
...
responseVolley = "";
getProductFromDataBase("6130127000035");
Log.d("responseVolley", responseVolley);
...
And my getProductFromDataBase is looking like this
public void getProductFromDataBase(final String bareCode) {
mPreferences = getApplicationContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
this.mEditor = mPreferences.edit();
String url = Constants.URL_SELECT_PRODUCT + "?" + Constants.PARAM_PRODUCT_CODE_BARE + bareCode;
Log.d("URL", url);
StringRequest stringRequest = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.d("response", response);
responseVolley = response;
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d("response", "EROOR");
}
}) {
protected HashMap<String, String> getParams() throws AuthFailureError {
Map<String, String> params = new HashMap<>();
return (HashMap<String, String>) params;
}
};
RequestHandler.getInstance(getApplicationContext()).addToRequestQueue(stringRequest);
}
When I am trying to show responseVolley it doesn't even show something in the Logcat ( I've tried many other solutions like shared preferences ) but nothing worked
Am I doing something wrong ?
Using Volley, you should verify these points :
Check and recheck the url string, if you did not deploy your web app, you should use the IP address you used start your server (http://loaclhost:port_number for example).
If your web app is not deployed on the internet yet, your server and your android app must be in the same network (try to make a hotspot from your PC and connect from your device).
In order to see a result in your response, you should return a string for example from the function that route the asked url, i.e. you should have a function in your web app that you want to send data to a function that catch your url in demande, you should return a string in that function.
You should also verify the error log, use a different tag from the response log tag.
Some times you should give some retry time (in case of weak connection):
stringRequest.setRetryPolicy(new RetryPolicy() {
#Override
public int getCurrentTimeout() {
return 50000;
}
#Override
public int getCurrentRetryCount() {
return 50000;
}
#Override
public void retry(VolleyError error) throws VolleyError {
}
}
PS: In the code you provided you are sending nothing, you should put strings you want to send like this:
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> params = new HashMap<>();
params.put("key", "value");
return params;
}
You should use callback method to do what you expect. With help of an interface, you can achieve what you actually want. If it doesn't work, let me know.
getProductFromDataBase("6130127000035");
OnResult onResult = new OnResult() {
#override
public void result(String responseVolley) {
Log.d("responseVolley", responseVolley);
}
};
Your getProductFromDataBase() method
interface OnResult {
void result(String responseVolley);
}
public void getProductFromDataBase(final String bareCode) {
mPreferences = getApplicationContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
this.mEditor = mPreferences.edit();
String url = Constants.URL_SELECT_PRODUCT + "?" + Constants.PARAM_PRODUCT_CODE_BARE + bareCode;
Log.d("URL", url);
StringRequest stringRequest = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.d("response", response);
onResult.result(response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d("response", "EROOR");
}
}) {
protected HashMap<String, String> getParams() throws AuthFailureError {
Map<String, String> params = new HashMap<>();
return (HashMap<String, String>) params;
}
};
RequestHandler.getInstance(getApplicationContext()).addToRequestQueue(stringRequest);
}

Send Raw Data in android using Volley

I am trying to send an http post request with raw data .
may be its a duplicate question.. nut i've tried a lot but didn't get any exact solution..
May be there is some minor mistake that i'm not able to understand..
The raw data format is described below
{result_data: [project,circuit]}
what I'm doing:
public void MakeStrRawRequest(final String Tag, String url, final String appData, final ResponseListener responseListener) {
//String uri = String.format(Locale.US, URL);
StringRequest stringRequest = new StringRequest(Request.Method.POST, url,
new com.android.volley.Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.d(TAG, "String Success :" + response);
}
},
new com.android.volley.Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, "String Error In Request :" + error.toString());
NetworkResponse response = error.networkResponse;
if (error instanceof ServerError && response != null) {
try {
String res = new String(response.data,
HttpHeaderParser.parseCharset(response.headers, "utf-8"));
// Now you can use any deserializer to make sense of data
//JSONObject obj = new JSONObject(res);
Logger.e(res);
} catch (UnsupportedEncodingException e1) {
// Couldn't properly decode data to string
e1.printStackTrace();
}
}
}
}) {
#Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
return super.parseNetworkResponse(response);
}
#Override
protected Map<String, String> getParams() throws AuthFailureError {
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("result_data", "[project,circuit]");
// {result_data: [project,circuit]}
return hashMap;
}
#Override
public byte[] getBody() throws AuthFailureError {
return appData.getBytes();
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
String AuthToken = "auto_token_value";
headers.put(ApiConstant.TOKEN_KEY, AuthToken);
return headers;
}
};
stringRequest.setRetryPolicy(new DefaultRetryPolicy(15000, DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
ApplicationData.getInstance().getRequestQueue().add(stringRequest);
}
Here is the response that i'm getting..
BasicNetwork.performRequest: Unexpected response code 400
I've tried both method to send data
1.in getParam() and
2. in getBody()
1. #Override
protected Map<String, String> getParams() throws AuthFailureError {
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("result_data", "[project,circuit]");
// {result_data: [project,circuit]}
return hashMap;
}
2.
#Override
public byte[] getBody() throws AuthFailureError {
return appData.getBytes();
}
getBody and getParams both are use to send parameters .So, You should call only one method at a time .If you want to send an arbitary string then use getBody() method and on the otherside if you want to send normal parameters then you should use getBody() method.For more detail you may see here

Android Volley: POST request - req.body inside of NodeJS REST API empty

I know its been discussed like a billion times, and I have read a couple of questions/answers and this one in particular seemed like a good example -> example. So now I have tried to recreate the code and added my getParams() as well as my getHeaders().
Awkwardly I get a HTTP Status Code 400:
E/Volley: [303] BasicNetwork.performRequest: Unexpected response code 400 for http://10.0.2.2:3000/classes
Since I have created the REST API I can see where this status code 400 comes from, its my NodeJS response if the req.body doesn't contain mAtt, mDatum, mRID, mVon. So now I know that my POST request is not properly working even tho I set my getParams()as well as my getHeaders() ...
Now, my guess would be that I'm setting Params but I'm fetching req.body.mAtt, req.body.mDatum , req.body.mRID, req.body.mVon, that would explain why my NodeJS returns the status code 400. If I fetched req.query.mAtt I would probably get something back?
Is there a certain method that need to be overridden by me, to actually set the body instead of the query params?
This is what my POST req looks like:
JsonObjectRequest JOPR = new JsonObjectRequest(Request.Method.POST,
myAcitveLessonPOSTUrl, null, new Response.Listener<JSONObject>(){
#Override
public void onResponse(JSONObject response) {
try {
VolleyLog.v("Response:%n %s", response.toString(4));
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.e("Error: ", error.getMessage());
}
}){
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/json");
return headers;
}
#Override
protected Map<String, String> getParams()
{
Map<String, String> params = new HashMap<String, String>();
params.put("mAtt", "+1");
params.put("mDatum", mDatum);
params.put("mRID", mRID);
params.put("mVon", mVon);
return params;
}
};
requestQ.add(JOPR);
Thank you!
I finally got it. I continued to search for answers and stumbled upon this question/answer link.
Since my REST API is looking for req.body variables, the getParams() have no effect. In order to send req.body variables the getBody() method has to be overridden.
So what I basically had to do was:
1) create a JSONObject
2) put my key:values inside the JSONObject
3) get the contents of my JSONObject into a String via toString()
4) #Override the getBody() method inside my JsonObjectRequest
Done.
So my corrected code looks like this:
JSONObject jsonBodyObj = new JSONObject();
try{
jsonBodyObj.put("mAtt", "+1");
jsonBodyObj.put("mDatum",mDatum);
jsonBodyObj.put("mRID",mRID);
jsonBodyObj.put("mVon",mVon);
}catch (JSONException e){
e.printStackTrace();
}
final String requestBody = jsonBodyObj.toString();
JsonObjectRequest JOPR = new JsonObjectRequest(Request.Method.POST,
myAcitveLessonPOSTUrl, null, new Response.Listener<JSONObject>(){
#Override
public void onResponse(JSONObject response) {
try {
VolleyLog.v("Response:%n %s", response.toString(4));
populateLessonDetails(myActiveLessonURLFiltered);
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.e("Error: ", error.getMessage());
}
}){
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/json");
return headers;
}
#Override
public byte[] getBody() {
try {
return requestBody == null ? null : requestBody.getBytes("utf-8");
} catch (UnsupportedEncodingException uee) {
VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s",
requestBody, "utf-8");
return null;
}
}
};
requestQ.add(JOPR);
Kudos to #dvdciri for his original question and Edits, what would eventually become this answer!

How to use Volley to POST a string in the body and to save the binary response to a file

I am currently using OkHttp, but I'd like to switch to Volley.
Maybe it is the late hour, but I can't seem to figure out how to send a POST request with just text in the body (in my app, the body is encrypted as a whole and then decrypted on the server side, and then split into params).
Also, my response should be a binary (not an image) that I'd like to save to a file.
I'm beginning to think that Volley isn't my best solution.
Help would be much appreciated.
Use getParams to add body in POSt, like here
url = "http://google.com";
StringRequest postRequest = new StringRequest(Request.Method.POST, url,
new Response.Listener<String>()
{
#Override
public void onResponse(String response) {
// response
}
},
new Response.ErrorListener()
{
#Override
public void onErrorResponse(VolleyError error) {
// error response
}
}
) {
#Override
protected Map<String, String> getParams()
{
Map<String, String> params = new HashMap<String, String>();
params.put("param1", "aaa");
params.put("param2", "bbb");
return params;
}
};
queue.add(postRequest);
Volley is not designed for sending/receiving big data and multipart request. Best would be to have data in response base64 encoded.
Volley offers a method getBody() which you can use to put any data into the HTTP request body:
#Override
public byte[] getBody() throws AuthFailureError {
byte[] body = new byte[0];
try {
body = mContent.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "Unable to gets bytes from content", e.fillInStackTrace());
}
return body;
}

Android Volley POST string in body

I'm trying to use Volley library to communicate with my RESTful API.
I have to POST string in the body, when I'm asking for the bearer Token. String should look like this:
grant_type=password&username=Alice&password=password123
And header:
Content-Type: application/x-www-form-urlencoded
More info about WebApi Individual Accounts:
http://www.asp.net/web-api/overview/security/individual-accounts-in-web-api
Unfortunately I can't figure out how can I solve it..
I'm trying something like this:
StringRequest req = new StringRequest(Request.Method.POST, URL, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
VolleyLog.v("Response:%n %s", response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.e("Error: ", error.getMessage());
}
}){
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put("grant_type", "password");
params.put("username", "User0");
params.put("password", "Password0");
return params;
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/x-www-form-urlencoded");
return headers;
}
};
I'm getting 400 Bad Request all the time.
I think that I'm actually sending request like this:
grant_type:password, username:User0, password:Password0
instead of:
grant_type=password&username=Alice&password=password123
I would be very grateful if anyone has any ideas or an advice..
To send a normal POST request (no JSON) with parameters like username and password, you'd usually override getParams() and pass a Map of parameters:
public void HttpPOSTRequestWithParameters() {
RequestQueue queue = Volley.newRequestQueue(this);
String url = "http://www.somewebsite.com/login.asp";
StringRequest postRequest = new StringRequest(Request.Method.POST, url,
new Response.Listener<String>()
{
#Override
public void onResponse(String response) {
Log.d("Response", response);
}
},
new Response.ErrorListener()
{
#Override
public void onErrorResponse(VolleyError error) {
Log.d("ERROR","error => "+error.toString());
}
}
) {
// this is the relevant method
#Override
protected Map<String, String> getParams()
{
Map<String, String> params = new HashMap<String, String>();
params.put("grant_type", "password");
// volley will escape this for you
params.put("randomFieldFilledWithAwkwardCharacters", "{{%stuffToBe Escaped/");
params.put("username", "Alice");
params.put("password", "password123");
return params;
}
};
queue.add(postRequest);
}
And to send an arbitary string as POST body data in a Volley StringRequest, you override getBody()
public void HttpPOSTRequestWithArbitaryStringBody() {
RequestQueue queue = Volley.newRequestQueue(this);
String url = "http://www.somewebsite.com/login.asp";
StringRequest postRequest = new StringRequest(Request.Method.POST, url,
new Response.Listener<String>()
{
#Override
public void onResponse(String response) {
Log.d("Response", response);
}
},
new Response.ErrorListener()
{
#Override
public void onErrorResponse(VolleyError error) {
Log.d("ERROR","error => "+error.toString());
}
}
) {
// this is the relevant method
#Override
public byte[] getBody() throws AuthFailureError {
String httpPostBody="grant_type=password&username=Alice&password=password123";
// usually you'd have a field with some values you'd want to escape, you need to do it yourself if overriding getBody. here's how you do it
try {
httpPostBody=httpPostBody+"&randomFieldFilledWithAwkwardCharacters="+URLEncoder.encode("{{%stuffToBe Escaped/","UTF-8");
} catch (UnsupportedEncodingException exception) {
Log.e("ERROR", "exception", exception);
// return null and don't pass any POST string if you encounter encoding error
return null;
}
return httpPostBody.getBytes();
}
};
queue.add(postRequest);
}
As an aside, Volley documentation is non-existent and quality of StackOverflow answers is pretty bad. Can't believe an answer with an example like this wasn't here already.
First thing, I advise you to see exactly what you're sending by either printing to the log or using a network sniffer like wireshark or fiddler.
How about trying to put the params in the body? If you still want a StringRequest you'll need to extend it and override the getBody() method (similarly to JsonObjectRequest)
I know this is old, but I ran into this same problem and there is a much cleaner solution imo found here: How to send a POST request using volley with string body?

Categories

Resources