When I use OkHttp to post I get a response like this (Instagram api)
{"access_token":"2222222.22222.2222222","user":{"username":"xxx","bio":"","website":"","profile_picture":"https:\/\/instagramimages-a.akamaihd.net\/profiles\/anonymousUser.jpg","full_name":"Test","id":"222222"}}
which I am unable to cast to a JsonObject (I think it is because of the weird way the urls are formatted).
But when I use HttpsUrlConnection everything works fine.
OkHTTP
private final OkHttpClient client = new OkHttpClient();
public static final MediaType MEDIA_TYPE_MARKDOWN
= MediaType.parse("text/plain");
//then in a function
String postBody="client_id="+Application.INSTAGRAM_CLIENT_ID
+"&client_secret="+Application.INSTAGRAM_SECRET_KEY
+"&grant_type=authorization_code"
+"&redirect_uri=" +Application.CALLBACKURL
+"&code=" + SharedPrefHelper.getSharedPerferenceData(context, SharedPrefHelper.SHARED_PREFERENCE_KEY_INSTAGRAM_CODE, "");
Request request = new Request.Builder()
.url(Application.TOKENURL)
.post(RequestBody.create(MEDIA_TYPE_MARKDOWN,postBody))
.build();
I use response.body.string() in the callback method to get the string and cast it to JsonObject.
if (response.code() == 200) {
try {
JSONObject jsonObject = new JSONObject(response.body().string());
} catch (JSONException e) {
}
}
How to fix this ?
ERROR :
org.json.JSONException: End of input at character 0 of
You can only use response.body().string() only once. I was calling it twice. First for logging the response and then again for json casting.
First thing:
You are probably getting a blank response. Its not null but the response is empty. So you are getting this error and not a NullPointerException
Have you logged it before converting in JSON? Checked it.
Second Thing:
You may have to try with GET if you are used POST currently or Vice Versa.
Related
I'm using Retrofit 2 to call API in Android App. I have a API, using POST, which have a String param in Query Tag. I do everything like doc suppose and I test this API successfully in Test Page. I can run another API correctly so the problem is not the way I use Retrofit 2.
Here is my interface:
#POST("/users/{userId}/get_list_friends")
Call<GetListFriendDataResponse> getListFriend(#Path("userId") int userId, #Query("list") String list, #Query("page") int page, #Query("size") int size, #Header("hash") String hash);
Here is my implementation:
ArrayList<String> id = new ArrayList<>();
id.add("4782947293");
JSONArray jsonArray = new JSONArray(id);
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("list", jsonArray);
} catch (JSONException e) {
e.printStackTrace();
}
String list = jsonObject.toString();
Log.e(TAG, "list: " + list);
apiInterface.getListFriend(21, list, 1,1,"AHHIGHTJGI").enqueue(new Callback<GetListFriendDataResponse>() {
#Override
public void onResponse(Call<GetListFriendDataResponse> call, Response<GetListFriendDataResponse> response) {
Log.e(TAG, " response code: "+ response.code());
}
#Override
public void onFailure(Call<GetListFriendDataResponse> call, Throwable t) {
}
});
I always get response code: 400 when use this API.
I'm focusing the "list" var. "list" is a JSON text but I wonder if method "jSon.toString()" is right to get a String from a JSONObject, which can using in Retrofit 2. List param form is:{"list":["12332"]} .
Please help me!
Questions
1) Why you are creating JSONObject and JSONArray on your own?
2) You are creating string using whatever you are creating json.
Eg: {list:["123","456"]}
you are trying pass whole json, I think, instead you need to pass just the array of string to the list key.
Request Sending
{
list:["123","456"]
}
suppose the above json is the request you want to send to server
Now, create model class goto http://jsonschema2pojo.org and paste your json and select json and gson at right side and click on preview.
It will show the classes to map you json to model. Use this model class to set the list to the key in your json
I found my problem. The JSON text contains some special character so I need to convert them to URL encode.
Correct request URL like this:
http://54.169.215.161:8080/users/29/add_friend?list=%7B%22list%22%3A%5B%2215536%22%5D%7D&platform=google
By using Retrofit 2, it uses the URL:
http://54.169.215.161:8080/users/29/add_friend?list={%22list%22:[%2215536%22]}&platform=google
So I get Bad Request Response code.
Retrofit 2 also provides method to convert char sequence to URL encode but it 's not enough. So I don't use Retrofit 's convert method by using this code: encode= true.
so my interface is:
#POST("/users/{userId}/get_list_friends")
Call<GetListFriendDataResponse> getListFriend(#Path("userId") int userId, #Query(value = "list",encoded = true) String list, #Query("page") int page, #Query("size") int size, #Header("hash") String hash);
And I manually convert JSON text to URL encode by code:
list = list.replace("{", "%7B");
list=list.replace("]", "%5D");
list=list.replace("[", "%5B");
list=list.replace(":", "%3A");
list=list.replace("}","%7D");
list = list.replace("\"", "%22");
That's all. Now I can get data by using API.
Suggestion: If u have the same problem, check the URL retrofit return in response and compare to correct URL to see special character, which is not converted to URL encode.
I am trying to fetch a list from a server. Problem is, Retrofit 2.0 is converting my request to an encoded request which is not acceptable to my server. So I need to remove that automatic encoding from the request. I have tried almost all solutions by putting encoded = true/false in the Request but it's not working at all.
Now, the situation is: All things are working good with "POST" Requests. Is there any similar way to do it with a "GET" Call? GET requests giving me "400 Bad Request" due to the encoded URL. The Main Issue with Encoding in GET.
POST call:
Working POST
#FormUrlEncoded
#POST("login")
Call<UserBean> getLogin(#FieldMap Map<String,String> params);
POST ENCODED URL:(working)
https://---.---.com/---/webservice/login?
jhobject=%7B%22data%22%3A%22%7B%5C%22username%5C%22%3A%5C%22abz%40cbv.com%5C%22%2C%5C%22password%5C%22%3A%5C%221234%40567%5C%22%2C%5C%22manufacturername%5C%22%3A%5C%22Android%5C%22%2C%5C%22modelname%5C%22%3A%5C%22XT1068%5C%22%2C%5C%22osversion%5C%22%3A%5C%223.4.42-g0a0ded4%5C%22%2C%5C%22countrycode%5C%22%3A%5C%22in%5C%22%2C%5C%22appversion%5C%22%3A%5C%221.0%5C%22%2C%5C%22imei%5C%22%3A%5C%22353325060286683%5C%22%2C%5C%22appfor%5C%22%3A%5C%22Sony%5C%22%7D%22%2C%22enc%22%3A%220%22%7D
Not Working GET
#Headers({"Content-Type:application/x-www-form-urlencoded"})
#GET("getlisting")
Call<MyBean> getListing(#QueryMap Map<String,String> params);
GET ENCODED URL:(Not working)
https://---.---.com/---/webservice/getlisting?
jhobject=%257B%2522data%2522%253A%257B%2522pageno%2522%253A%25221%2522%252C%2522totalpages%2522%253A%25220%2522%252C%2522recordperpages%2522%253A%252210%2522%252C%2522cstatus%2522%253A%25221%2522%252C%2522reportid%2522%253A%252253%2522%257D%252C%2522enc%2522%253A%25220%2522%252C%2522token%2522%253A%252209046d74-c047-4534-be0b-050dadad18b8%257E%257E23717%2522%257D
You are doing double encoding
in post
jhobject=%7B
in get
jhobject=%257B
I experienced same problem until I remove this line #FormUrlEncoded it seems like GET don't need to be encoded or what I don't understand that part
You may wanna remove this line on your code and try it #Headers({"Content-Type:application/x-www-form-urlencoded"})
I experienced same problem with GET and retrofit, here is the solution with retrofit
1- Load URL server :
Retrofit retrofit = new Retrofit.Builder().baseUrl("URL")
.addConverterFactory(GsonConverterFactory.create()).build();
service = retrofit.create(CallApiService.class);
2- Load config api :
public interface CallApiService {
#GET("URI")
Call<ResponseBody> getProfessions( #Header("x-req-user-id") String x_req_user_id);
}
3- Call api and mapping data:
RetrofitLoader retrofitLoader = new RetrofitLoader();
CallApiService service = retrofitLoader.getServiceLoader();
Call<ResponseBody> retrofitCall = service.getProfessions("8");
LOGGER.info("conncet to url : GET " + retrofitCall.request().url());
Response<ResponseBody> response;
try {
response = retrofitCall.execute();
if (!response.isSuccessful())
throw new IOException("Unexpected code " + response);
String responseData = response.body().string();
LOGGER.info("getProfessions Data : " + responseData);
try {
JSONObject jsonObject = new JSONObject(responseData);
return jsonObject.toString();
} catch (JSONException e) {
LOGGER.error("Error jsonObject : " + e);
}
} catch (IOException e) {
e.printStackTrace();
}
return "";
I previously implemented the following post request with volley but now i want to use it for retrofit.
So my rest webservice is the following
www.blahblahblah.com/webservice.svc/
I have a function (Person) that is called in the webservice that accepts the following jsonobject
JSONObject jsonObject = new JSONObject();
JSONObject searchCriteria = new JSONObject();
jsonObject.put("FullName", "frank jones");
jsonObject.put("DOB", "06-04-1978");
jsonObject.put("Age", "28");
jsonObject.put("Reason", "Search");
searchCriteria.put("searchCriteria", jsonObject);
So in volley i call www.blahblahblah.com/webservice.svc/Person
and pass the above jsonobject.
Works perfectly
So for Retrofit i've used the same logic, create my jsonobject and pass it in the request
So i use the same url www.blahblahblah.com/webservice.svc/
Create my Post
#POST("Person")
Call<PersonResponseData> getPersonAccess(#Body Object body);
so then my code to get the response
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(urlSearch)
.addConverterFactory(GsonConverterFactory.create())
.build();
RetrofitService service = retrofit.create(RetrofitService.class);
Call<PersonResponseData> personResponseDataCall = service.getPersonAccess(searchCriteria);
personResponseDataCall.enqueue(new Callback<PersonResponseData>() {
#Override
public void onResponse(Response<PersonResponseData> response, Retrofit retrofit) {
int statuscode = response.code();
PersonResponseData personResponseData = response.body();
}
#Override
public void onFailure(Throwable t) {
}
});
I just get a 404 error, any ideas.
As i said this works perfectly in volley but I've done something wrong in retrofit.
Thanks for your help
You can review this question link here is a explanation for use retrofit 2 with POST request
That's only guess, but try following:
1) in Call declaration specify it, not Call getPersonAccess, but Call<PersonResponseData> getPersonAccess;
2) make POJO instead of JSON object and use it as a body instead of passing Object into getPersonAccess call.
I am attempting to call a put method on my server using OkHttp from an Android application.
This is the api method signature:
public void Put(int userId, string regId)
{
}
This is the Android code to call the above method:
private boolean SendGCMRegIdToServer(String registrationId, Integer userId) throws IOException {
HttpUrl url = new HttpUrl.Builder()
.scheme("http")
.host(serverApiHost)
.addPathSegment("AppDashboard")
.addPathSegment("api")
.addPathSegment("GCM/")
.build();
MediaType JSON
= MediaType.parse("application/json; charset=utf-8");
String json = "{'userId':" + userId + ","
+ "'regId':'" + registrationId + "'"
+ "}";
RequestBody requestBody = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.put(requestBody)
.build();
//this should post the data to my server
Response response = client.newCall(request).execute();
if(response.code() == 400)
return false;
return true;
}
Now the problem is I am getting the error code 405 in the response saying Method not allowed, but I cannot see where the problem is because I can successfully call the method using Postman on the server itself as below:
http://localhost/AppDashboard/api/GCM?userId=5®Id=123
I'm thinking it may have something to do with an integer or string being passed incorrectly in the JSON string, but cannot see why this isn't working.
i had the same problem and server was returning 405 . after some search i realized that is a configuration problem on IIS that does not let put requests. so there is no problem in android code and you should config your server to let this kind of requests.
see this , this and this
Ok thanks for replies guys but seems I was getting a little confused between the two methods I was using to pass the params to my API.
Here's what I did:
changed the signature of the method to post with a param [FromBody] as a Model (only supports one paramater)...
public void Post([FromBody]UserGcmRegIdModel model)
{
}
I was then able to change my method call to the following using a nicer JSONBuilder and using .post in the request builder rather than .put
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("UserId", userId);
jsonObject.put("RegId", registrationId);
} catch (JSONException e) {
e.printStackTrace();
}
String json = jsonObject.toString();
RequestBody requestBody = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();
I still don't know if there is a problem with put() methods on IIS but using a post in my case was absolutely fine so I'm going with that...
I see two different approaches in your REST api calls. In the one of OkHttp you send a PUT method with a JSON object serialized, and in POSTMAN you send a PUT (although I guess you do a GET) request with the parameters within the URL, I mean not in JSON body structure.
Anyway, HTTP 405 is telling you that your backend does not support the PUT method, and probably it's expecting a POST method with the "X-HTTP-Method-Override:PUT" HTTP header since POST is more standard method in REST than PUT.
What would I do is check your POSTMAN request carefully and adjust the one of Android to be the same method, parameters and headers, not more.
Answer Update (as question has been updated)
Of course there is a problem with that verb, as I said above IIS handles only the standard methods and PUT is not one of those. You have three choices:
Change your PUT to POST.
Use POST with X-HTTP-Method-Override to PUT. (reference)
Modify IIS config to support non standard REST methods. I
personally wouldn't suggest the 3rd one, since it's attached to the
backend config (e.g. imagine you change IIS to NancyFX).
I am hoping someone might be able to help me out.
I have a Django server that is returning JSON to an iOS application. On the Django server, we are using
return HttpResponse(json.dumps(session_dict),mime_type)
to return the JSON to the client as (via Wireshark)
2f
{"session": "bcb493fb21ae8fcd9152e1924b3e5d9a"}
0
This response is somehow valid to the iOS application able to be parsed by the iOS JSON client libraries. This does not look like valid Json to me so I am surprised it works.
However, if I use the following in Android, I get an error:
Value session of type java.lang.String cannot be converted to JSONObject.
jsonObjSend.put("username", strUserName);
jsonObjSend.put("password", strPassword);
Add a nested JSONObject (e.g. for header information)
JSONObject header = new JSONObject();
header.put("deviceType","Android"); // Device type
header.put("deviceVersion","2.0"); // Device OS version
header.put("language", "es-es");
jsonObjSend.put("header", header);
// Output the JSON object we're sending to Logcat:
Log.i(TAG, jsonObjSend.toString(2));
} catch (JSONException e) {
e.printStackTrace();
}
try {
// Send the HttpPostRequest and receive a JSONObject in return
JSONObject jsonObjRecv = HttpClient.SendHttpPost(URL, jsonObjSend);
String sessionId = jsonObjRecv.getString("session");
Any suggestions?
Thank you,
Greg
Does your HttpClient.sendHttpPost method return a JSONObject? Not sure if it parses the response body from the HTTP POST into a JSONObject automatically. If it doesn't, then you would have to do that using the JSONTokener or use a library like Gson.
google's GSON may be a better choice you can convert an instance to json string directly such as
User user =new User("tom","12");
Gson gson =new Gson();
json=gson.toJson(user);