I'm trying to communicate between Android and a Flask server I've set up on AWS. I have some data I've put inside a JSONObject, and I'm sending that over a POST request to the server.
The Flask server receives this JSON, parses it, and even does the appropriate manipulations. However, when I send a Response back to Android, it doesn't seem to identify it at all.
I believe I'm going wrong in the Flask return part, but I don't know where exactly.
Here's the Flask return code:
parsed_results = parse_text(results)
#json_x = json.dumps({'id':str(status.inserted_id), 'Result':'OK', 'data': parsed_results})
return Response(json.dumps({'id': str(status.inserted_id), 'Result': 'OK', 'data': parsed_results, 'raw_data': results}), mimetype='application/json'), 200
if __name__ == "__main__":
app.run(host='0.0.0.0', debug=True)
Here's the Android Listener code:
JsonObjectRequest request = new JsonObjectRequest(
Request.Method.POST,
URL,
data,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.d("JSON_TAG", response.toString());
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
}
}
)
{
#Override
protected Map<String, String> getParams() throws AuthFailureError {
return super.getParams();
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
//return super.getHeaders();
Map<String,String> headers = new HashMap<>();
headers.put("Content-Type","application/json");
return headers;
}
};
The Android application just stays idle. Where am I going wrong? Any help would be greatly appreciated. Thanks!
I solved the issue, guys. The problem was very apparent - a mismatched return statement from the server. By using jsonify, I was able to return the data to the server.
from flask import jsonify
results = parse_results(data)
return jsonify(results)
Worked like a charm!
Related
JSON response from a remote server
{"status":"success",
"data":{"auth_token":"9389e656c90e11c451443657c8e",
"user":{"active_location":" Airport"}}}
I need to store the auth_token and pass to the remote server as the header,
tried addHeader("key1", "value1");
but still not working, need help
To send headers for belly request, you need to override getHeaders() method. Inside method create a map and put your key-value pairs and return the the map.
JsonObjectRequest request = new JsonObjectRequest(requestMethod, yourUrl, postData(if any), new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
//TODO parse your response
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
//TODO handle error
}
}){
//Here is the place where you can add your headers
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put("key1", "value1");
return params;
}
};
Also if you need to pass any request parameters you can do that in the same way by overriding getParams() method.
For more details check the volley tutorial
You can simply use Base64 to encode the token string and put it in SharedPrefs, then read and decode to send in a header.
Peeps, I have some problem in understanding the working of volley library, so answer with proper material which can guide me to unobserved aspects of volley is what I am looking forward to.
How does my POST parameters are bind in network request. When I send params after overriding getParams() and by sending jsonObject directly in network request I don't receive any response but some server errors.
Since I am testing my backend on Postman, what postman actually does(my Observation) is it bind the params in url itself. When I copy paste the url in my android code it responds positively.
So, should I code to append my params to url or there's another way round?
I have alredy tried making changes to getHeaders() but it doesn't respond too!
You should use a JsonObjectRequest with a jsonObject containing all your params.
HashMap<String, String> params = new HashMap<String, String>();
params.put("token", "8327483274823");
JSONObject jsonObject = new JSONObject(params);
JsonObjectRequest req = new JsonObjectRequest(URL,jsonObject ,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
//Do stuff here
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
//Handle Errors here
}
});
I am trying to use volley to add a score to my database. I have tested my URL with a POST request using Postman, I have also manually typed the URL with parameters in the android app to the POST request, and that works. so I assume that my issue is in my android code? Or do I have to use the getParams to manually build the url string?
the error I'm getting from my backend:
Error: ER_BAD_FIELD_ERROR: Unknown column 'undefined' in 'field list'
which makes me think that my parameters aren't getting initialized prior to the StringRequest being called.
public void submitHighScore(){
StringRequest postRequest = new StringRequest(Request.Method.POST, url,
new Response.Listener<String>()
{
#Override
public void onResponse(String response) {
// response
Toast.makeText(context, response , Toast.LENGTH_SHORT).show();
}
},
new Response.ErrorListener()
{
#Override
public void onErrorResponse(VolleyError error) {
// error
Toast.makeText(context, "Error: unable to submit Score " + error , Toast.LENGTH_SHORT).show();
}
}
){#Override
protected Map<String, String> getParams() throws com.android.volley.AuthFailureError
{
Map<String, String> params = new HashMap<String, String>();
params.put("playerName", "Android test");
params.put("playerScore", "3000");
return params;
}
};
HighScoreSingleton.getInstance(context).addToRequestQueue(postRequest);
For those who may or may not believe me about my code on my server side.
app.post('/api/highScore', function(req,res){
var con = mysql.createConnection({
host: "xxxx",
user: "xxxx",
password: "xxxx",
database: "xxxx"
});
if(req.query!=null){ //
console.log(typeof req.query.playerName);
con.query(`INSERT INTO xxxx (playerScore, playerName) VALUES
(${req.query.playerScore}, "${req.query.playerName}" )`, // async, runs callback aka function
function(err,rows){
if(err) throw err;
res.setHeader('Content-Type', 'text/plain');
res.send('Updated High Score');
});
con.end();
}
});
Thank you in advance, It's very possible I'm overlooking something very simple, otherwise I will just modify my URL in my StringRequest as this seems a bit silly, given the getParams method.
I Hope this will work for you.
I think you need to add header
Override this method.
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String,String> params = super.getHeaders();
if(params==null)params = new HashMap<>();
params.put("Content-Type","text/plain");
return params;
}
How do I send a DELETE Request using Volley (Android) to a REST Api with parameters like access_token and username. I have tried almost everything on Internet but still I am getting a 400 error Message.
I have tried sending the same DELETE request using PostMan and it works perfectly fine.
Here is the Error:
E/Volley﹕ [1112] BasicNetwork.performRequest: Unexpected response code 400 for http://myserverip/messages/2
and Here is the Java code that I am using:
String URI = "http://myserverip/messages/2";
JsonObjectRequest request = new JsonObjectRequest(Request.Method.DELETE,URI,null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Toast.makeText(contextm,response.toString(),Toast.LENGTH_SHORT).show();
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
}){
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> headers = super.getHeaders();
if (headers == null
|| headers.equals(Collections.emptyMap())) {
headers = new HashMap<String, String>();
}
headers.put("access_token", "access_token");
headers.put("username", "username");
return headers;
}
};
MyApp.getInstance().addToRequestQueue(request);
Might not be really useful but here is the working DELETE request preview from PostMan
DELETE /messages/1 HTTP/1.1
Host: serveripaddress
Cache-Control:no-cache
Content-Type: application/x-www-form-urlencoded
access_token=SPAVYaJ7ea7LzdeQYrBTsIRssuGbVpJI8G9XSV0n&username=whit3hawks
You can easily achieve this if you put the following instead of null in ... new JsonObjectRequest(Request.Method.DELETE,URI,null,new Response.Listener<JSONObject>() { ...
final JSONObject object = new JSONObject();
try {
object.put("access_token", "SPAVYaJ7ea7LzdeQYrBTsIRssuGbVpJI8G9XSV0n");
object.put("username", "whit3hawks");
} catch (Exception e) {
e.printStackTrace();
}
So your Request should look like this:
... new JsonObjectRequest(Request.Method.DELETE,URI,object,new Response.Listener<JSONObject>() { ...
You posted a long time ago, but maybe someone else will need this some time.
I am successfully sending headers in volley while using DELETE with this code:
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/json");
return headers;
just tried it and works like a charm.
EDIT:
if you're using a Mac, try checking with Charles what exactly it is you are sending,
on a PC you can try fiddler.
also, error 400 means 'Bad Input', so the server is either getting more info then it should, or less then he expects.
and keep in mind that DELETE in Volley acts as a GET, make sure you are sending an empty body with the request.
hope that helped somehow.. happy coding
How to make a JSON request in volley where I need to send an authentification header and JSON object in body and I expect only an status code 200 answer
JsonObjectRequest request = new JsonObjectRequest(
method,
url,
myJsonObject,
responseListener,
errorListener) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
String creds = String.format("%s:%s", login, password);
String auth = "Basic " + Base64.encodeToString(creds.getBytes(), Base64.DEFAULT);
headers.put("Authorization", auth);
return headers;
}
};
new Response.Listener<String>(){
#Override
public void onResponse(String response) {
Toast.makeText(getActivity(), response, 1000).show();
}
I tried different kinds of response listeners with string or JSON object, object, but always there is an error:
android volley org.json.JSONException: End of input at character 0 of
Or is there any other kind of request in volley which supports and json object and authentification header in body and response is just a http status code ?
I know its an old question but i thought i still answer this as my answer might help people in future -
You need to create a custom class that extends Request class and in that class override these methods
#Override
protected Response parseNetworkResponse(NetworkResponse response) {
return Response.success(response.statusCode, HttpHeaderParser.parseCacheHeaders(response));
}
#Override
protected void deliverResponse(Integer statusCode) {
mListener.onResponse(statusCode);
}
This is the heart and soul of the class.
For full code and explanation check out my blog on the topic -
Getting a server response status 200 from Android Volley library
link 1
Hope it helps,
Thanks
Thanks to Varundroid and Itai Hanski. It's correct, you just need to subclass the JsonObjectRequest.
For convenience here's my override:
public class MyJsonObjectRequest extends JsonObjectRequest {
#Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
// here's the new code, if jsonString.length() == 0 don't parse
if (jsonString.length() == 0) {
return Response.success(null, HttpHeaderParser.parseCacheHeaders(response));
}
// end of patch
return Response.success(new JSONObject(jsonString), HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JSONException je) {
return Response.error(new ParseError(je));
}
}
}
So I just use that instead of JsonObjectRequest.
Not too pretty, not too ugly.
The JsonObjectRequest is used when you expect the network response to be a JSON object. Since you're not expecting that, you shouldn't be using it.
Volley comes with a few predefined popular types of requests for ease of use, but you can always create your own. I suggest making a custom request based on JsonObjectRequest, but with a different implementation of the parseNetworkResponse() method that does not expect the response to be a JSON object, since you aren't receiving one. You can add any other changes you need there.
No need to create custom class which extends Request as #varundroid stated.
You can just override parseNetworkResponse method instead of onResponse method and return success response with empty JSONObject().
Following is the code I'm using to overcome the same problem you are facing. I hope this helps you too
#Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
if (response != null && response.data.length == 0)
return Response.success(new JSONObject(), null);
else
return super.parseNetworkResponse(response);
}