Python Requests to Java OkHttp for Android - android

I have the following code working perfectly in Python:
login_data = {'identifier': 'something#email.com', 'password': 'Password'}
url = "https://www.duolingo.com/2017-06-30/login?fields="
p = requests.post(url, data = json.dumps(login_data))
if p.status_code is 200:
print("SUCCESS")
else:
print("ERROR")
I want to convert it to Java using OkHttp to be able to implement it in Android Studio.
I have written the following code but it gives Status Code: 422 which according to Google means Unprocessable Entity:
OkHttpClient client = new OkHttpClient();
String url = "https://www.duolingo.com/2017-06-30/login?fields=";
String login_data = "{\"identifier\": \"something#email.com\", \"password\": \"Password\"";
RequestBody body = RequestBody.create(login_data, MediaType.parse("application/json"));
Request postRequest = new Request.Builder()
.url(url)
.post(body)
.build();
client.newCall(postRequest).enqueue(new Callback()
{
#Override
public void onFailure(#NotNull Call call, #NotNull IOException e)
{
Log.i("TAG", "ERROR - " + e.getMessage());
}
#Override
public void onResponse(#NotNull Call call, #NotNull Response response) throws IOException
{
if (response.isSuccessful())
{
Log.i("LOG", "SUCCESS - " + response.body().string());
}
else
{
Log.i("LOG", "FAILED. Status Code: " + String.valueOf(response.code));
}
}
});
All help is appreciated!

You have a missing closing bracket in the request body at java implementation.
"{\"identifier\": \"something#email.com\", \"password\": \"Password\"}"

Related

Separate Class for OkHttp Requests

I use OkHttp for requests to my raspberry. I am thinking about putting the requests in a separate class.
Currently I have one method to send requests. The code is as follows:
private void sendRequest(String url, JSONObject json) {
Log.d(TAG, "sendRequest: Das Json: " + json);
// Authentication for the request to raspberry
OkHttpClient.Builder client = new OkHttpClient.Builder();
client.authenticator(new Authenticator() {
#Override
public Request authenticate(Route route, Response response) throws IOException {
String credential = Credentials.basic("username", "password");
return response.request().newBuilder()
.header("Authorization", credential)
.build();
}
});
// Sending out the request to the raspberry
OkHttpClient okHttpClient = client.build();
RequestBody body = RequestBody.create(null, new byte[]{});
if( json != null) {
body = RequestBody.create(MediaType.parse(
"application/json"),
json.toString()
);
}
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
okHttpClient.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
Log.d(LOG, "Big Fail");
e.printStackTrace();
}
#Override
public void onResponse(Call call, Response response) throws IOException {
try {
ResponseBody responseBody = response.body();
if( !response.isSuccessful() ) {
Log.d(TAG, "onResponse: We are in !response.successful()");
throw new IOException("Response not successful: " + response );
}
Log.d(LOG, "onResponse: Response is: " + responseBody.string());
} catch (Exception e) {
e.printStackTrace();
Log.d(LOG, "onResponse: failed!" + e);
}
}
});
}
Here is an example how the sendRequest() function is called:
private void makePremixCall(Premix premix) {
JSONArray jsonArray = new JSONArray();
ArrayList<Premixable> usedPremixables = premix.getUsedPremixables();
for(Premixable usedPremixable: usedPremixables) {
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("Silo", usedPremixable.getmSilo());
jsonObject.put("Gramm", usedPremixable.getmKgPerCow() * mFeeding.getmNumberOfCows());
jsonArray.put(jsonObject);
} catch (JSONException e) {
e.printStackTrace();
}
}
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("Components", jsonArray);
sendRequest("http://192.168.178.49:5000/evaluatePost", jsonObject);
} catch (JSONException e) {
e.printStackTrace();
Log.d(TAG, "makePremixCall: " + e);
}
}
My problem with this: I would like to have a separate class, which offers the function makePremix(Premix premix) and other functions that I need.
The only solution that comes to my mind is implementing the requests synchronously in the separate class and call that separate class in an AsyncTask in the class I am working in.
Do I oversee something? Is there a way to create a separate class and still use the OkHttp enqueue method?
You could extract makePremix(Premix premix) in a separate class and make sendRequest() public (or maybe package-private depending on your use case).
public void sendRequest(String url, JSONObject json)
However since sendRequest is generic and can be used by any other makeAnotherCall() in some other class you would need to get back result of every requests. Hence you can extract the Callback out of sendRequest()
public void sendRequest(String url, JSONObject json, Callback callback)
Now your sendRequest will look like
private void sendRequest(String url, JSONObject json) {
Log.d(TAG, "sendRequest: Das Json: " + json);
// Authentication for the request to raspberry
OkHttpClient.Builder client = new OkHttpClient.Builder();
client.authenticator(new Authenticator() {
#Override
public Request authenticate(Route route, Response response) throws IOException {
String credential = Credentials.basic("username", "password");
return response.request().newBuilder()
.header("Authorization", credential)
.build();
}
});
// Sending out the request to the raspberry
OkHttpClient okHttpClient = client.build();
RequestBody body = RequestBody.create(null, new byte[]{});
if( json != null) {
body = RequestBody.create(MediaType.parse(
"application/json"),
json.toString()
);
}
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
okHttpClient.newCall(request).enqueue(callback);
}
Hope it makes sense!
Also as a side note, see that you are creating a new OkHttp Client every time you call sendRequest. You could probably optimise memory here by caching the client and reusing it.

Getting Alexa Profile information

I am Authorizing an Alexa android application , using the below code .
How can I get profile information from the below code ?
private static final String[] APP_SCOPES= {"alexa:all"};
String PRODUCT_DSN = Settings.Secure.getString(mContext.getContentResolver(),
Settings.Secure.ANDROID_ID);
Bundle options = new Bundle();
String scope_data = "{\"alexa:all\":{\"productID\":\"" + mProductId +
"\", \"productInstanceAttributes\":{\"deviceSerialNumber\":\"" +
PRODUCT_DSN + "\"}}}";
options.putString(AuthzConstants.BUNDLE_KEY.SCOPE_DATA.val, scope_data);
options.putBoolean(AuthzConstants.BUNDLE_KEY.GET_AUTH_CODE.val, true);
options.putString(AuthzConstants.BUNDLE_KEY.CODE_CHALLENGE.val, getCodeChallenge());
options.putString(AuthzConstants.BUNDLE_KEY.CODE_CHALLENGE_METHOD.val, "S256");
options.putBoolean(AuthzConstants.BUNDLE_KEY.PROFILE.val, true);
mAuthManager.authorize(APP_SCOPES, options, authListener);
Finally i found the answer , Need Fetch the access token, then call the api:
https://api.amazon.com/user/profile
Header: Authorization", Bearer
access_token
Eg :
String url = "https://api.amazon.com/user/profile";
OkHttpClient client = ClientUtil.getTLS12OkHttpClient();
Request request = new Request.Builder()
.url(url)
.addHeader("Authorization", "Bearer " + access_token)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, final IOException e) {
}
#Override
public void onResponse(Call call, Response response) throws IOException {
String s = response.body().string();
}
});

How to pass body to OKHttp message?

I have found this example below to send HTTP POST message with OKHttp.
I do not understand how to pass a body string to RequestBody. Why it takes two argument?
RequestBody formBody = new FormBody.Builder()
.add("message", "Your message")
.build();
Request request = new Request.Builder()
.url("http://rhcloud.com")
.post(formBody).addHeader("operation", "modifyRecords")
.build();
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
#Override
public void onResponse(Call call, Response response) throws IOException {
try (ResponseBody responseBody = response.body()) {
if (!response.isSuccessful())
throw new IOException("Unexpected code " + response);
Headers responseHeaders = response.headers();
for (int i = 0, size = responseHeaders.size(); i < size; i++) {
System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
System.out.println(responseBody.string());
}
}
});
}
}
I'm not sure if I understand what you mean quite right, but if you are asking why the FormBody .add() takes two arguments, it's because these are Key-Value-Pairs. The first parameter is the name and the second the value.
Anyway I think this example shows a clearer way how to post a string:
public static final MediaType MEDIA_TYPE_MARKDOWN
= MediaType.parse("text/x-markdown; charset=utf-8");
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
String postBody = ""
+ "Releases\n"
+ "--------\n"
+ "\n"
+ " * _1.0_ May 6, 2013\n"
+ " * _1.1_ June 15, 2013\n"
+ " * _1.2_ August 11, 2013\n";
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(RequestBody.create(MEDIA_TYPE_MARKDOWN, postBody))
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}

How to get response body in okhttp when code is 401?

I am using OkHttp 3.2.0 and here is code for building request object:
MediaType JSON = MediaType.parse(AppConstants.CONTENT_TYPE_VALUE_JSON);
RequestBody body = RequestBody.create(JSON, requestBody);
HttpUrl url = new HttpUrl.Builder()
.scheme("http")
.host("192.168.0.104")
.port(8080)
.addPathSegment("mutterfly-server")
.addPathSegment("j_spring_security_check")
.addQueryParameter("j_username", jsonObject.getString("emailId"))
.addQueryParameter("j_password", jsonObject.getString("password"))
.build();
request = new Request.Builder()
.addHeader(AppConstants.CONTENT_TYPE_LABEL, AppConstants.CONTENT_TYPE_VALUE_JSON)
.addHeader(AppConstants.ACCEPT_LABEL, AppConstants.CONTENT_TYPE_VALUE_JSON)
.url(url)
.post(body)
.build();
And here is how I parse the response:
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
}
#Override
public void onResponse(Call call, final Response response) throws IOException {
String respBody;
if (response.isSuccessful()) {
if (response.body() != null) {
respBody = response.body().string();
Log.i(TAG, respBody);
response.body().close();
if (AppMethods.checkIfNull(loginParserListener)) {
try {
final VUser user = AppMethods.getGsonInstance().fromJson(respBody, VUser.class);
} catch (Exception e) {
}
}
}
} else {
switch (response.code()){
case 401:
String body="HTTP_UNAUTHORIZED";
break;
}
}
}
});
This is the ideal response(from web rest client) when authentication is failed.
{"msgDesc":"The username or password you entered is incorrect..","statusCode":401}
EDIT:
response.toString() returns
Response{protocol=http/1.1, code=401, message=Unauthorized, url=http://192.168.0.104:8080/mutterfly-server/j_spring_security_check?j_username=s#s.s&j_password=1}
response.body().toString() returns
okhttp3.internal.http.RealResponseBody#528ae030
I want to fetch the msgDesc which is in response body. Is there any method which will return this string?
Try this:
switch (response.code()){
case 401:
JsonObject object=new JsonObject(response.body().string());
String body=object.getString("msgDesc");
break;
}
It's quite weird but Square, the company behind OkHttp, has chosen to not use 'toString()' but 'string()' as method for getting the body as a String.
So this works;
String string = response.body().string();
//convert to JSON and get your value
But this doesn't:
String string = response.body().toString();
401 means permission denied.
Check if your token is valid or user/password is correct.

Retrofit POST raw string body

I am using Retrofit to send a POST request to a server. The body of the POST must be in the form jdata={"key1":"value1",...} along with a Content-Type header set to application/x-www-form-urlencoded. I found a similar question but the accepted answer is not working.
Here's what I tried -
My interface
public interface APIHandler {
#Headers("Content-Type: application/x-www-form-urlencoded")
#FormUrlEncoded
#POST(URL)
Call<ResponseBody> getdata(#Field("jdata") String jdata);
}
Call function
public void load() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("BASE_URL")
.addConverterFactory(GsonConverterFactory.create())
.build();
// prepare call in Retrofit 2.0
APIHandler iAPI = retrofit.create(APIHandler.class);
String requestBody = "{\"id\":\"value\",\"id1\":\"value2\"}"
Call<ResponseBody> call = iAPI.getData(requestBody);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> c, Response<ResponseBody> response) {
if (response.isSuccess()) {
ResponseBody result = response.body();
String gs = new Gson().toJson(result);
Log.d("MainActivity", "response = " + gs + " status: " + statusCode);
} else {
Log.w("myApp", "Failed");
}
}
#Override
public void onFailure(Call<ResponseBody> c, Throwable t) {
}
});
}
But I receive response = null and status = 200. What am I doing wrong? The expected response is only a string and not a JSON array.
I am leaving this here so that it helps someone.
The above code is correct. As I mentioned in the last line, a plain string response was expected. But since it is not a JSON response, the conversion probably did not work and the response was null. The only solution I could find was to directly convert the response to string -
try {
stresp = response.body().string()
Log.d("MainActivity", "response = " + stresp + " status: " + statusCode);
} catch (IOException e) {
//Handle exception
}
There might be a better way to handle this but that worked for me!
You can use like that. I have tested this and it working fine
public interface APIHandler {
#POST(URL)
Call<ResponseBody> getdata(#Body JsonObject body);
}
Request body:
JsonObject requestBody = new JsonObject();
requestBody.addProperty("id", "value1");
requestBody.addProperty("id1", "value2");
Prepare call in Retrofit 2.0
APIHandler iAPI = retrofit.create(APIHandler.class);
And Call function :
Call<ResponseBody> call = iAPI.getData(requestBody);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> c, Response<ResponseBody> response) {
if (response.isSuccess()) {
String result = response.body().string();
Log.d("MainActivity", "response = " + result);
} else {
Log.w("myApp", "Failed");
}
}
#Override
public void onFailure(Call<ResponseBody> c, Throwable t) {
}
});

Categories

Resources