I have teaching myself how to develop Android applications and I recently started using the Volley library for networking. I have been able to send basic requests with it. I was experimenting with Pocket's API to see if my app could fetch the items. Their documentation page mentions that I have to send a JSON request like so
POST /v3/oauth/request HTTP/1.1
Host: getpocket.com
Content-Type: application/json; charset=UTF-8
X-Accept: application/json
{"consumer_key":"1234-abcd1234abcd1234abcd1234",
"redirect_uri":"pocketapp1234:authorizationFinished"}
So I made a JSONObject in my app, added the key consumer_key with the value of my consumer key, then added in the key redirect_uri with its respective value. I sent this JSONObject as a request to the required URL as a POST request using Volley. The response code I received was 403, which is caused by a bad consumer key. I have double-checked the consumer key, so the problem lies with my request. How should I go about making the JSON request? Do I have to add the extra data, like Content-Type? If so, how?
If it is not too much, could you point me to a beginner-friendly resource on JSON, since I do not have much knowledge about web development?
Thank you.
What request methode do you use on your code? I am facing issue when using StringRequest method. Its work when use JsonObjectRequest method.
Here is how to create request besides on my experience.
Create Header Parameter
final Map<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/json");
headers.put("X-Accept", "application/json");
headers.put("consumer_key", "your-consumer-key");
headers.put("redirect_uri", "https://kamus.nusagates.com");
Create JSONObject From headers
JSONObject obj = new JSONObject(headers);
Create JsonObjectRequest
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest("https://getpocket.com/v3/oauth/request", obj, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
//get all response data
Log.d("respon", String.valueOf(response));
try {
//get code from response
Log.d("respon code", response.getString("code"));
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
}) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
return headers;
}
#Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
String server = String.valueOf(response.headers);
Log.d("header", server);
return super.parseNetworkResponse(response);
}
};
Add the request to The Queue
RequestQueue queue = Volley.newRequestQueue(MainActivity.this);
queue.add(jsonObjectRequest);
May this could help you solve your problem.
Cheers
Related
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
}
});
Good evening,
Following this discussion, we are facing a new problem. We are trying to make a POST request (login) work on Android using the Volley library to make HTTP requests. The /login/ works well on Postman or Advanced REST Client, but it doesn't when using Volley. We have seen many other persons facing this problem and trying to find an answer on SO, but the only answer was to disable CSRF and we really don't want to do this.
On Postman, the response is 200 OK.
On Android Volley, the response is 403 forbidden : CSRF cookie not set.
Since we set CSRF_USE_SESSIONS as True, it doesn't make sense for us.
CSRF_USE_SESSIONS is True in Django
The library used to make HTTP requests on Android is Volley
We don't want to disable CSRF protection/middleware (I'm pointing this because many answers in other posts talking about this problem suggest to disable CSRF, but we are using it for both web client and mobile apps)
Here is the Java request :
private void loginPost(final String csrf) {
RequestQueue queue = Volley.newRequestQueue(getActivity());
String url = "https://api.ourapi.com/login/";
JSONObject object = new JSONObject();
try {
object.put("username", "hello");
object.put("password", "world");
System.out.println(object);
} catch (JSONException e) {
Log.d("Dude", "RIIIIIIIIIIIIIIIIIIIP");
}
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest
(Request.Method.POST, url, object, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
// response
System.out.println("######################################");
System.out.println(response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// TODO Auto-generated method stub
System.out.println(error);
}
}
) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put("Accept", "application/json");
params.put("X-CSRFToken", csrf);
System.out.println(params);
return params;
}
};
queue.add(jsonObjectRequest);
}
Here is the Django Login class-based view :
class Login(LoginView):
form_class = AuthenticationForm
template_name = 'users/login.html'
def post(self, request, *args, **kwargs):
if request.META.get('HTTP_ACCEPT') == 'application/json':
form = self.get_form()
if not form.is_valid():
print(form.errors.as_text())
return JsonResponse({'error': form.errors.as_text()}, status=400)
return super().post(request, *args, **kwargs)
We think that we are missing something in the Volley request headers or somewhere else. Can you guys help us ?
EDIT:
Here are our CSRF settings:
CSRF_COOKIE_AGE = None
CSRF_COOKIE_DOMAIN = '.ourapi.com'
CSRF_COOKIE_HTTPONLY = True
CSRF_COOKIE_SECURE = True
CSRF_USE_SESSIONS = True
Self answer, here !
I kind of misunderstood how CSRF and session cookies work in Django. In the process_view function of the CsrfViewMiddleware, the reason message 403 forbidden - CSRF cookie not set is triggered when the CSRF token is None (see here). The csrf_token value comes from the _get_token(request) method from the same class, but it seems that the value returned is None (see here).
All we had to do was simply sending the session cookie to the server with the CSRF token in the header as X-CSRFToken !
So I'm running into a problem when calling rest-auth/user/.
I am able to login and obtain the key from said login, but from that I'm not sure how to use it in regards to rest-auth/user/. I've tried using it with GET in volley, as well as POSTing it in volley. But everytime I try to do so, I get a 403 back saying credentials were not provided. I've also tried saving the token to Android's SharedPreferences.
I'm not sure what could be wrong or how to fix this problem, so any help would be appreciated.
My code looks like this:
getUserQueue = Volley.newRequestQueue(this);
JSONObject jsObj = new JSONObject();
try {
jsObj.put("token", token);
} catch (JSONException e) {
e.printStackTrace();
}
JsonObjectRequest jsObjRequest = new JsonObjectRequest
(Request.Method.GET, "http://hurst.pythonanywhere.com/supportal/rest-auth/user/", jsObj, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
result = response.getString("username");
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
}
});
// add the request object to the queue to be executed
getUserQueue.add(jsObjRequest);
From comments it is clear that you are using different authentication schemes for rest, will explain these,
SessionAuthentication
For authenticating session authentication you need persistant cookie implementation in android volley, check here for this, where Set-Cookie header is parsed from server api response & send over next requests.
BasicAuthentication
In Basic authentication scheme, username & password are send over every request ( after login ?), with Authorization header value ( Base64 encoded).To check how to implement this check here
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> params = new HashMap<String, String>();
String creds = String.format("%s:%s","USERNAME","PASSWORD");
String auth = "Basic " + Base64.encodeToString(creds.getBytes(), Base64.DEFAULT);
params.put("Authorization", auth);
return params;
}
JSONWebTokenAuthentication
In JWT authentication scheme, after successful login you will get a JWT token, you need to send this token in every request that need user authorization, for this to work, set Authorization header value with JWT token_after_login;Only difference with Basic authentication is how header is send.
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> params = new HashMap<String, String>();
String auth = "JWT " + token // token you will get after successful login
params.put("Authorization", auth);
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
I'm trying to send a JSON as string (not as object) to the server (in this case it's a WebAPI). I always get a error code 500.
I succeeded to get response from the server when the request was GET and without sending data to the server. this achieved by JsonObjectRequest.
Now, I trying to send a POST request with JSON as string. For that I try
JsonObjectRequest
StringRequest
GsonRequest
JsonRequest - here I supplied my json in the requestBody
Before using volley, I used other methods to send request to server which require to simply build an object, serialized to json (string) and pass via StringEntity.
I can't understand where should I pass the json in the request. or what I'm doing wrong.
I don't exactly understand why do you want to send the JSON as a string and not as an object. Nevertheless, in your WebAPI endpoint you should put a breakpoint in the Post method of the ApiController and see whether the request gets there or not.
Probably, you're mixing the content-types of the request. If you want to send a simple string request from Volley, you should just use the StringRequest and send there the JSON text. Thus, in the WebAPI POST method you must get the string without being deserialized to JSON. I answered once a similar question of how this string request should be made here.
However, as I said before I would suggest using always JSON requests which includes the contentType:"application/json" header, and receive requests in the WebAPI deserialized.
url = "yoururl"; StringRequest postRequest = new StringRequest(Request.Method.POST, url,
new Response.Listener<String>()
{
#Override
public void onResponse(String response) {
// response
Log.d("Response", response);
}
},
new Response.ErrorListener()
{
#Override
public void onErrorResponse(VolleyError error) {
// error
Log.d("Error.Response", response);
}
} ) {
#Override
protected Map<String, String> getParams()
{
Map<String, String> params = new HashMap<String, String>();
params.put("your_field", youJSONObject.toString());
return params;
} }; queue.add(postRequest);
Try in this way to make the post (it should work with json obj or array)