I am trying to create the Android version of a curl GET request. Works great in terminal, but fails in the app.
The curl request (urls are not real):
curl -d '{"detail": "Y"}' -H "Content-Type:application/json" -X GET -H "Auth-Token:longstringhereforauthtoken" https://api.myendpoint.com/REST/GSLB/zone-to-get-records-from.com/fqdn-of-domain.com/
It gives back what I need without any issue.
Well, now I want to use that request in a Volley request in Android, however, I am getting back:
Unexpected response code 406 for https://api.myendpoint.com/REST/GSLB/zone-to-get-records-from.com/fqdn-of-domain.com/
The code where I'm attempting the request is as follows (will show relevant variables that are set beforehand):
private String url;
private String request;
private String searchRequest;
String selected = getIntent().getStringExtra("node");
String token = getIntent().getStringExtra("token");
url = getResources().getString(R.string.api_url);
request = url + "/Session/";
searchRequest = url + "/GSLB/"+selected+"/"+selected+"/";
ProgressDialog searchDialog = new ProgressDialog(MainActivity.this);
searchDialog.setMessage("Getting zone info...");
searchDialog.show();
JSONObject object = new JSONObject();
try {
object.put("Content-Type", "application/json");
object.put("Auth-Token", token);
object.put("detail", "Y");
} catch(JSONException e) {
Log.d(TAG, e.getMessage());
}
Log.d(TAG, "Selected "+icon+", Token: "+token);
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, searchRequest, object,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
searchDialog.dismiss();
Log.d(TAG, String.valueOf(response));
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
searchDialog.dismiss();
if( error instanceof NetworkError) {
Log.d(TAG, error.toString());
Log.d(TAG, "Request to "+searchRequest+" FAILED...");
} else if( error instanceof ServerError) {
Log.d(TAG, "Request to "+searchRequest+" FAILED...");
Log.d(TAG, error.toString());
} else if( error instanceof AuthFailureError) {
Log.d(TAG, error.toString());
Log.d(TAG, "Request to "+searchRequest+" FAILED...");
} else if( error instanceof ParseError) {
Log.d(TAG, error.toString());
Log.d(TAG, "Request to "+searchRequest+" FAILED...");
} else if( error instanceof NoConnectionError) {
Log.d(TAG, error.toString());
Log.d(TAG, "Request to "+searchRequest+" FAILED...");
} else if( error instanceof TimeoutError) {
Log.d(TAG, error.toString());
Log.d(TAG, "Request to "+searchRequest+" FAILED...");
}
}
});
RequestQueue searchRequestQueue = Volley.newRequestQueue(MainActivity.this);
searchRequestQueue.add(jsonObjectRequest);
That is when I receive the error:
BasicNetwork.performRequest: Unexpected response code 406 for https://api.myendpoint.com/REST/GSLB/zone-to-get-records-from.com/fqdn-of-domain.com/
Before this activity, I have a LoginActivity that does a similar request, which is where the token comes from in the GET request. It sends credentials and received the Auth-Token. This one works, so I am unsure of why the previous snippet is failing.
The Login request:
JSONObject object = new JSONObject();
try {
object.put("user_name", usernameEditText.getText().toString());
object.put("customer_name", customernameEditText.getText().toString());
object.put("password", passwordEditText.getText().toString());
object.put("Content-Type", "application/json");
} catch(JSONException e) {
Log.d(TAG, e.getMessage());
}
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, request, object,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
if(response != null) {
Log.d("JSON", String.valueOf(response));
String token = null;
pDialog.dismiss();
try {
token = response.getJSONObject("data").getString("token");
Log.d("JSON", token);
} catch (JSONException e) {
Toast.makeText(LoginActivity.this, "" + e.getMessage(),Toast.LENGTH_LONG).show();
e.printStackTrace();
}
Intent loginIntent = new Intent(LoginActivity.this, SelectActivity.class);
loginIntent.putExtra("token", token);
LoginActivity.this.startActivity(loginIntent);
} else {
Toast nullToast = Toast.makeText(LoginActivity.this, "Invalid Credentials\nPlease try again", Toast.LENGTH_LONG);
nullToast.show();
usernameEditText.getText().clear();
customernameEditText.getText().clear();
passwordEditText.getText().clear();
}
}
}
I have done these requests in both PHP and cURL, but can't seem to understand why it's failing with Android. I feel like my syntax is correct, but perhaps I'm missing something?
The clue was in the request response error code (406). Instead of this:
JSONObject object = new JSONObject();
try {
object.put("Content-Type", "application/json");
object.put("Auth-Token", token);
object.put("detail", "Y");
} catch(JSONException e) {
Log.d(TAG, e.getMessage());
}
I used the getHeaders() method to send my headers, like so:
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put("Content-Type", "application/json");
params.put("Auth-Token", token);
params.put("detail", "Y");
return params;
}
Though I do not understand why my object.put() does not work (It was in any tutorials I viewed, so I need to research more), this was what fixed it. I'm now getting my response successfully.
406 http error code stays for "not acceptable". This means that your request has an incorrect header. I believe that JsonObjectRequest doesn't manage headers, but the request body.
In order to work on request header you need to override the getHeaders() method from VolleyRequest class, something like:
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put("Content-Type", "application/json");
params.put("Auth-Token", token);
params.put("detail", "Y");
return params;
}
Related
I am trying to upload an audio file in android to a server. The problem is that I have no idea how to write upload code in Android or if there are any libraries or API that I can use.
I am new to Android development with no experience of server side. I have very little knowledge of how to connect and communicate with a server, post data to server, fetch data from server and what responses to look for from the server.
I am trying to find to find a tutorial or a guide which can show how to upload in Android and also explain what is being done in the code. Any guide or suggestions on how to learn to communicate with server would be very helpful.
Use this code using volley for network requests to upload text, multipart(audio, image, etc) :
String url = "http://yoururl.com";
VolleyMultipartRequest multipartRequest = new VolleyMultipartRequest(Request.Method.POST, url, new Response.Listener<NetworkResponse>() {
#Override
public void onResponse(NetworkResponse response) {
String resultResponse = new String(response.data);
try {
JSONObject result = new JSONObject(resultResponse);
String status = result.getString("status");
String message = result.getString("message");
if (status.equals(Constant.REQUEST_SUCCESS)) {
// tell everybody you have succed upload image and post strings
Log.i("Messsage", message);
} else {
Log.i("Unexpected", message);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
NetworkResponse networkResponse = error.networkResponse;
String errorMessage = "Unknown error";
if (networkResponse == null) {
if (error.getClass().equals(TimeoutError.class)) {
errorMessage = "Request timeout";
} else if (error.getClass().equals(NoConnectionError.class)) {
errorMessage = "Failed to connect server";
}
} else {
String result = new String(networkResponse.data);
try {
JSONObject response = new JSONObject(result);
String status = response.getString("status");
String message = response.getString("message");
Log.e("Error Status", status);
Log.e("Error Message", message);
if (networkResponse.statusCode == 404) {
errorMessage = "Resource not found";
} else if (networkResponse.statusCode == 401) {
errorMessage = message+" Please login again";
} else if (networkResponse.statusCode == 400) {
errorMessage = message+ " Check your inputs";
} else if (networkResponse.statusCode == 500) {
errorMessage = message+" Something is getting wrong";
}
} catch (JSONException e) {
e.printStackTrace();
}
}
Log.i("Error", errorMessage);
error.printStackTrace();
}
}) {
#Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<>();
params.put("api_token", "gh659gjhvdyudo973823tt9gvjf7i6ric75r76");
params.put("name", mNameInput.getText().toString());
params.put("location", mLocationInput.getText().toString());
params.put("about", mAvatarInput.getText().toString());
params.put("contact", mContactInput.getText().toString());
return params;
}
#Override
protected Map<String, DataPart> getByteData() {
Map<String, DataPart> params = new HashMap<>();
// file name could found file base or direct access from real path
// for now just get bitmap data from ImageView
params.put("avatar", new DataPart("file_avatar.jpg", AppHelper.getFileDataFromDrawable(getBaseContext(), mAvatarImage.getDrawable()), "image/jpeg"));
params.put("cover", new DataPart("file_cover.jpg", AppHelper.getFileDataFromDrawable(getBaseContext(), mCoverImage.getDrawable()), "image/jpeg"));
return params;
}
};
VolleySingleton.getInstance(getBaseContext()).addToRequestQueue(multipartRequest);
For more code you can visit this url
I've been searching this site and others for solutions on making a POST request with a JSON body, but the solutions I've found don't seem to work for me. For reference, here is a successful request I've made using curl from the terminal:
curl -I -X POST -H "x-app-id:myID" -H "x-app-key:myKey"
-H "Content-Type:application/json" -H "x-remote-user-id:0"
https://trackapi.nutritionix.com/v2/natural/exercise -d '{
$+ "query":"ran 3 miles",
$+ "gender":"female",
$+ "weight_kg":72.5,
$+ "height_cm":167.64,
$+ "age":30
$+ }'
My attempts to convert this for an android app led me to volley, and searching around led me to use the following snippet:
try {
RequestQueue requestQueue = Volley.newRequestQueue(this);
JSONObject jsonBody = new JSONObject();
jsonBody.put("query", "ran 3 miles");
jsonBody.put("gender", "female");
jsonBody.put("weight_kg", 72.5);
jsonBody.put("height_cm", 167.64);
jsonBody.put("age", 30);
final String mRequestBody = jsonBody.toString();
String url = "https://trackapi.nutritionix.com/v2/natural/exercise";
StringRequest stringRequest = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.i("LOG_RESPONSE", response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("LOG_RESPONSE", error.getMessage());
}
}) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<>();
params.put("x-app-id", "myID");
params.put("x-app-key", "myKey");
params.put("Content-Type", "application/json");
params.put("x-remote-user-id", "0");
return params;
}
#Override
public String getBodyContentType() {
return "application/json; charset=utf-8";
}
#Override
public byte[] getBody() throws AuthFailureError {
try {
return mRequestBody == null ? null : mRequestBody.getBytes("utf-8");
} catch (UnsupportedEncodingException uee) {
VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s", mRequestBody, "utf-8");
return null;
}
}
#Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
String responseString = "";
if (response != null) {
responseString = String.valueOf(response.statusCode);
}
return Response.success(responseString, HttpHeaderParser.parseCacheHeaders(response));
}
};
requestQueue.add(stringRequest);
} catch (JSONException e) {
e.printStackTrace();
}
The API dictates that the data must be sent in the body, which is why I've excluded the getParams function. This snippet seems to work for everybody else on the internet, but I consistently get 400 messages from it. I've also converted the same curl request into a request in postman, and it works great there as well. Does anyone have any insight as to where I went wrong?
EDIT: Here's a link to the api as requested
Are you sure you are passing correct id in x-app-idand other fields? Because as per the logs, it says "x-app-id" = "myId"
You need to pass the actual id of your application.
Also,
You have already defined the content-type inside getBodyContentType() so don't mention it in getHeaders() or do the opposite.
And as per API documentation , x-remote-user-id isn't required. Maybe this is the reason why your request returned an error of 400
I use this method to send out requests.
You would use this method like this.
executePost("https://trackapi.nutritionix.com/v2/natural/exercise", mRequestBody, API_KEY);
Note, for me, as you will see, I have different API keys for a prod env or lower env. So you may not need API_KEY section... but looking at your headers, you will.. :)
public static String executePost(String targetURL, String requestJSON, String apikey) {
HttpURLConnection connection = null;
InputStream is = null;
try {
//Create connection
URL url = new URL(targetURL);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
//TODO may be prod or preprod api key
if (apikey.equals(Constants.APIKEY_PREPROD)) {
connection.setRequestProperty("Authorization", Constants.APIKEY_PREPROD);
}
if (apikey.equals(Constants.APIKEY_PROD)){
connection.setRequestProperty("Authorization", Constants.APIKEY_PROD);
}
connection.setRequestProperty("Content-Length", Integer.toString(requestJSON.getBytes().length));
connection.setRequestProperty("Content-Language", "en-US");
connection.setUseCaches(false);
connection.setDoOutput(true);
//Send request
DataOutputStream wr = new DataOutputStream (
connection.getOutputStream());
wr.writeBytes(requestJSON);
wr.close();
//Get Response
try {
is = connection.getInputStream();
} catch (IOException ioe) {
if (connection instanceof HttpURLConnection) {
HttpURLConnection httpConn = (HttpURLConnection) connection;
int statusCode = httpConn.getResponseCode();
if (statusCode != 200) {
is = httpConn.getErrorStream();
}
}
}
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
StringBuilder response = new StringBuilder(); // or StringBuffer if Java version 5+
String line;
while ((line = rd.readLine()) != null) {
response.append(line);
response.append('\r');
}
rd.close();
return response.toString();
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
I also want to make something else clear. This code is used on my local machine, it is not customer facing. The security of the code was not and is not an issue for my use case. Make sure you security store your API keys.
I'm testing the inter media API and I am trying it using this code below. I used volley for this:
String url = "https://api.infermedica.com/v2/diagnosis";
JSONArray evidence = new JSONArray();
JSONObject evidence1 = new JSONObject();
try {
evidence1.put("id", "s_1193");
evidence1.put("choice_id", "present");
} catch (JSONException e) {
e.printStackTrace();
}
try {
evidence.put(0,evidence1);
} catch (JSONException e) {
e.printStackTrace();
}
JSONObject postparams = new JSONObject();
try {
postparams.put("sex", "male");
postparams.put("age", 30);
postparams.put("evidence", evidence);
} catch (JSONException e) {
e.printStackTrace();
}
Log.e("DATA:", postparams.toString());
JsonObjectRequest jsonObjReq = new JsonObjectRequest(Request.Method.POST,
url, postparams,
new Response.Listener() {
#Override
public void onResponse(Object response) {
Log.e("DATA: ", response.toString());
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// As of f605da3 the following should work
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);
Log.e("DATA:" , obj.toString());
} catch (UnsupportedEncodingException e1) {
// Couldn't properly decode data to string
e1.printStackTrace();
} catch (JSONException e2) {
// returned data is not JSONObject?
e2.printStackTrace();
}
}
}
}
) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("app-id", "MY-APP-ID");
headers.put("app-key", "MY-APP-KEY");
headers.put("authorization", "Basic Og==");
headers.put("Content-type", "application/json");
return headers;
}
};
Log.e("DATA: " , "calling volley");
RequestQueue requestQueue = Volley.newRequestQueue(this);
requestQueue.add(jsonObjReq);
After running it and checking the logs here is the result:
E/DATA:: {"sex":"male","age":30,"evidence":
[{"id":"s_1193","choice_id":"present"}]}
E/DATA:: calling volley
E/Volley: [236] BasicNetwork.performRequest: Unexpected response code 400
for https://api.infermedica.com/v2/diagnosis
E/DATA:: {"message":"bad request"}
I tried the logged json in Postman and it was accepted:
Here is the screenshot of my postman result
I've been looking for answers around here, I already added the content-type, and I made sure that my keys are correct. Am I using the volley correctly. Your help will be much appreciated.
I tested my REST service in POSTMAN and it works. I should get something like this:
{
"msg": "the user was successfully created"
...
}
but in my android app in debug cannot find the response. Have I missed something or am I doing something wrong? Thanks!
private void registerUser(final String firstName, final String lastName,
final String email, final String password) {
pDialog.setMessage("Registering ...");
showDialog();
try {
RequestQueue requestQueue = Volley.newRequestQueue(this);
JSONObject jsonBody = new JSONObject();
jsonBody.put("first_name", firstName);
jsonBody.put("last_name", lastName);
jsonBody.put("email", email);
jsonBody.put("password", password);
final String requestBody = jsonBody.toString();
StringRequest stringRequest = new StringRequest(Request.Method.POST, AppConfig.URL_REGISTER, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.d(TAG, "Register Response: " + response);
hideDialog();
...
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("VOLLEY", error.toString());
}
}) {
#Override
public String getBodyContentType() {
return "application/json";
}
#Override
public byte[] getBody() throws AuthFailureError {
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;
}
}
#Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
String responseString = "";
if (response != null) {
responseString = String.valueOf(response.statusCode);
}
return Response.success(responseString, HttpHeaderParser.parseCacheHeaders(response));
}
};
requestQueue.add(stringRequest);
} catch (JSONException e) {
e.printStackTrace();
}
In debug, the block
#Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
String responseString = "";
if (response != null) {
responseString = String.valueOf(response.statusCode);
}
return Response.success(responseString, HttpHeaderParser.parseCacheHeaders(response));
}
displays this:
I have no JSON response.
You don't see any json data because you are not generating any json response from you side. The response you see on Postman is from the api service. You have a success response from your program (i.e. Status code 201) and that's the only thing you are sending back to the client.
if (response != null) {
responseString = String.valueOf(response.statusCode);
}
You have to manipulate the response (in parseNetworkResponse module) and forward the relevant info you want to your client.
I am making a Json request and I get the data and place it in a list view but some of the strings i get have accents or 'ç' and it doesn't appear correctly.
For example, the string is 'Bragança' and i receive 'Bragança' or 'à' and get 'Ã'. If i do the request in the browser, all works properly.
My request.
public void makeJsonArrayRequest() {
RequestQueue queue = AppController.getInstance().getRequestQueue();
queue.start();
JsonArrayRequest Req = new JsonArrayRequest(urlJsonObjUtilizadas,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
Log.d(TAG, response.toString());
// Parsing json
for (int i = 0; i < response.length(); i++) {
try {
JSONObject ementaObj = response.getJSONObject(i);
Ementa ementa = new Ementa();
ementa.setCantina(ementaObj.getString("cantina"));
ementa.setDescricao(ementaObj.getString("descricao"));
ementa.setEmenta(ementaObj.getString("ementa"));
ementa.setPreco(ementaObj.getInt("preco"));
ementaItems.add(ementa);
} catch (JSONException e) {
e.printStackTrace();
}
}
// notifying list adapter about data changes
adapter.notifyDataSetChanged();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + error.getMessage());
}
}) {
//**
// Passing some request headers
//*
#Override
public Map<String, String> getHeaders() {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/json; charset=UTF-8");
return headers;
}
};
// Add the request to the RequestQueue.
AppController.getInstance().addToRequestQueue(Req);
}
I think this is because of the wrong content type encoding header. You are supposed to use UTF-8 as encoding. Maybe this is working in the browsers because the headers are not case-sensitive (unlike Android).
Take a look here for a solution. Essentially they are manually overriding the charset.
please try to use this code for sending and receiving JSON with utf-8 encoding:
try {
URL url = new URL("your url");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
OutputStreamWriter writer = new OutputStreamWriter(
conn.getOutputStream(), "UTF-8");
String request = "your json";
writer.write(request);
writer.flush();
System.out.println("Code:" + conn.getResponseCode());
System.out.println("mess:" + conn.getResponseMessage());
String response = "";
BufferedReader reader = new BufferedReader(new InputStreamReader(
conn.getInputStream(), "UTF-8"));
String line;
while ((line = reader.readLine()) != null) {
response += line;
}
System.out.println(new String(response.getBytes(), "UTF8"));
writer.close();
reader.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
You should add the request header charset to UTF-8. For example if your request will be as json, you should add this header to the request:
"Content-type": "Aplicación/json; utf-8"
I use Volley too and this way works for me.
Regards.
Check this sample, this way i am using, look the header section
public class Estratek_JSONString extends JsonRequest<String>{
Activity Act;
Priority priority;
public Estratek_JSONString(int m, String url, JSONObject params,
Listener<String> listener, ErrorListener errorListener,Activity act, Priority p) {
super(m,url,params.toString(),listener,errorListener);
this.Act=act;
this.priority=p;
}
public Estratek_JSONString(int m, String url,
Listener<String> listener, ErrorListener errorListener,Activity act, Priority p) {
// super constructor
//super(m,url,params.toString(),listener,errorListener);
super(m,url,null,listener,errorListener);
this.Act=act;
this.priority=p;
}
#Override
public Map<String, String> getHeaders() {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/json; charset=utf-8");
headers.put("Authorization", "Bearer "+Tools.Get_string(Act.getApplicationContext(),Global_vars.Access_token));
return headers;
}
//it make posible send parameters into the body.
#Override
public Priority getPriority(){
return priority;
}
#Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString =
new String(response.data, HttpHeaderParser.parseCharset(response.headers));
return Response.success(new String(jsonString),
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
}
}
}