Accessing REST API in Android Using Request Headers - android

I have a question about the proper syntax and order of code in regards to accessing a REST API.
I am trying to access a database that I made on an mBaas called backendless.com. (The following data information is specific to this mBaas but my question is more about the general process of accessing REST API's in Android)
According to their tutorial to bulk delete (https://backendless.com/documentation/data/rest/data_deleting_data_objects.htm) I need a URL that queries my database for a specific value and then deletes it. I have that value. They also need 3 request headers (application-id, secret key, application type).I have those as well.
I utilized all of this information in an ASyncTask class that technically should open the url, set the request headers, and make the call to the REST API. My only issue is, I have no idea if I'm missing some kind of code here? Is my current code in proper order? Every time my class is executed, nothing happens.
I also get a log cat exception in regards to my URL: java.io.FileNotFoundException: api.backendless.com/v1/data/bulk/...
The URL does not lead to anything when I place it in my browser but I'm told that it shouldn't since the browser sends it as a GET request.
Anyway, here is my ASyncTask Class with all of the info. Does anyone know if this code looks correct or am I missing something here? I'm new to making these type of calls and don't really understand the roll that request-headers play in accessing REST APIs. Please let me know. Thank you!
class DeleteBulkFromBackEnd extends AsyncTask<Void,Void,String>{
final String API_URL = "https://api.backendless.com/v1/data/bulk/LocalPhoneNum?where%3DuserEmailID%3Dmark#gmail.com";
#Override
protected String doInBackground(Void... params) {
HttpURLConnection urlConnection = null;
try {
URL url = new URL(API_URL);
urlConnection = (HttpURLConnection)url.openConnection();
urlConnection.setRequestProperty( "application-id","12345678" );
urlConnection.setRequestProperty( "secret-key","12345678" );
urlConnection.setRequestProperty( "application-type", "REST" );
urlConnection.connect();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
Log.d("Contact","ERROR " + e.toString() );//IO Exception Prints in log cat not recognizing URL
e.printStackTrace();
}finally {
urlConnection.disconnect();
}
return null;
}
}

I recommend you to use okhttp for easy network access.
And check the response code and response body.
In your build.gradle:
compile 'com.squareup.okhttp3:okhttp:3.4.1'
Your AsyncTask will be like this:
class DeleteBulkFromBackEnd extends AsyncTask<Void, Void, String> {
final String API_URL = "https://api.backendless.com/v1/data/bulk/LocalPhoneNum?where%3DuserEmailID%3Dmark#gmail.com";
final OkHttpClient mClient;
public DeleteBulkFromBackEnd(OkHttpClient client) {
mClient = client;
}
#Override
protected String doInBackground(Void... params) {
try {
Request request = new Request.Builder()
.url(API_URL)
.delete()
.header("application-id", "12345678")
.header("secret-key", "12345678")
.header("application-type", "REST")
.build();
Response response = mClient.newCall(request).execute();
Log.d("DeleteBulkFromBackEnd", "Code: " + response.code());
Log.d("DeleteBulkFromBackEnd", "Body: " + response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
Execute the AsyncTask like this:
OkHttpClient client = new OkHttpClient();
void someMethod() {
...
new DeleteBulkFromBackEnd(client).execute();
...
}

As I've commented, here's the solution:
class DeleteBulkFromBackEnd extends AsyncTask<Void,Void,String>{
final String API_URL = "https://api.backendless.com/v1/data/bulk/LocalPhoneNum?where%3DuserEmailID%3Dmark#gmail.com";
#Override
protected String doInBackground(Void... params) {
HttpURLConnection urlConnection = null;
try {
URL url = new URL(API_URL);
urlConnection = (HttpURLConnection)url.openConnection();
urlConnection.setRequestProperty( "application-id","12345678" );
urlConnection.setRequestProperty( "secret-key","12345678" );
urlConnection.setRequestProperty( "application-type", "REST" );
urlConnection.setRequestMethod("DELETE");
urlConnection.connect();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
Log.d("Contact","ERROR " + e.toString() );//IO Exception Prints in log cat not recognizing URL
e.printStackTrace();
}finally {
urlConnection.disconnect();
}
return null;
}
}

Related

Why does using the 'search' function in the YouTube Data API use up so much of my quota?

I've been trying to develop an application that returns the first video result for a keyword (as well as getting its content details). This is done multiple times in a session (let's say, like 30 times). If all I'm doing is reading data from 1 result each time (from the "Calculating quota usage" section of their docs), then why is it that I use up all 10,000 of my daily units with a few test runs of my application?
Here's my specific code:
private class GetVideoDuration extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
String sURL = "https://www.googleapis.com/youtube/v3/videos?id=" + params[0] + "&part=contentDetails&key=" + API_KEY;
String var = null;
try {
// Connect to the URL using java's native library
URL url = new URL(sURL);
URLConnection request = url.openConnection();
request.connect();
// Convert to a JSON object to print data
JsonParser jp = new JsonParser(); //from gson
JsonElement root = jp.parse(new InputStreamReader((InputStream) request.getContent())); //Convert the input stream to a json element
Log.d("rootJSON", root.toString());
Log.d("urlJSON", url.toString());
JsonObject video = null;
try {
video = root.getAsJsonObject().get("items").getAsJsonArray().get(0).getAsJsonObject().get("contentDetails").getAsJsonObject();
} catch (IndexOutOfBoundsException e) {
e.printStackTrace();
Log.e("Chief", "It looks like we've exceeded our quota for the day :(");
}
var = video.get("duration").getAsString();
} catch (IOException e) {
e.printStackTrace();
// contDets = contentDetails
Log.d("Error parsing contDets", e.getMessage());
ERROR_STATE = true;
}
return var;
}
}
I'm aware of the option to apply for a higher quota, but it just seems like something's wrong. Any help would be greatly appreciated.

Log message to sumo logic from Android client

I've got a requirement to log message from the Android client. Is there any sumo logic API to log message from the Android application?
You can post your log message/ any message from your Android application to Summo Logic cloud-based log management.
Summo Logic provides Web Services/ REST to perform POST, GET Request.
You just need to post your data on the request body and mention your
Sumo collection endpoint as well as UniqueHTTPCollectorCode.
REST Service/ Web Service : https://[SumoEndpoint]/receiver/v1/http/[UniqueHTTPCollectorCode]
For Instance:
"https://endpoint1.collection.us2.sumologic.com/receiver/v1/http/SanTC12dhaV1oma90Vvb..."
You can use Retorfit / Volley library for REST Communication .
I have given a below pseudo code which conveys the basic REST Communication in background through Android Async Task.
I strictly recommend to use the above mentioned libraries.
public static String performPostRequest(String summoUrl, String payload,
Context context) throws IOException {
URL url = new URL(summoUrl);
HttpURLConnection uc = (HttpURLConnection) url.openConnection();
String line;
StringBuffer jsonString = new StringBuffer();
uc.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
uc.setRequestMethod("POST");
uc.setDoInput(true);
uc.setInstanceFollowRedirects(false);
uc.connect();
OutputStreamWriter writer = new OutputStreamWriter(uc.getOutputStream(), "UTF-8");
writer.write(payload);
writer.close();
try {
BufferedReader br = new BufferedReader(new InputStreamReader(uc.getInputStream()));
while((line = br.readLine()) != null){
jsonString.append(line);
}
br.close();
} catch (Exception ex) {
ex.printStackTrace();
}
uc.disconnect();
return jsonString.toString();
}
Async task
new AsyncTask<String, String, String>() {
#Override
protected String doInBackground(String... params) {
try {
String response = makePostRequest(""https://endpoint1.collection.us2.sumologic.com/receiver/v1/http/ZaVnC4dhaV1oma90Vvb..."",
// Sample JSON Data "
{ \"organization": \"organization.name\",
\"environment": \"environment.name\",
\"apiProduct": \("apiproduct.name"),
\"proxyName": \("apiproxy.name"),
\"appName": \("developer.app.name"),
\"verb": \("request.verb"),
\"url": '' + \("client.scheme") + '://' + \("request.header.host") + \("request.uri"),
\"responseCode": \("message.status.code"),
\"responseReason": \("message.reason.phrase"),
\"clientLatency": total_client_time,
\"targetLatency": total_target_time,
\"totalLatency": total_request_time
}", getApplicationContext());
// Hard coded Success as response from Server, replace with this as per your need
return "Success";
} catch (IOException exception) {
exception.printStackTrace();
return exception.getMessage();
}
}
}.execute("");
For more information, Please refer the documentation from Official Sumo Webpage
https://help.sumologic.com/Send-Data/Sources/02Sources-for-Hosted-Collectors/HTTP-Source/Upload-Data-to-an-HTTP-Source

java.io.EOFException on Android Client (API 23) when POSTing Object to Jersey

I want to implement a basic authentication using an Android Client and a Glassfish 4.1.1 Server (communicating through REST-Service).
The Service is working quite well (proven by POSTMAN and another C#-Client) but on Android, it's driven me crazy by now.
It also appears that the object-to-send is received as 'null' on the server side, also an annoying "EOFException" is thrown on the Android Side.
Server side (works fine)
#POST
#Consumes({MediaType.APPLICATION_JSON})
#Produces({MediaType.APPLICATION_JSON})
public Account validate(Account acc)
{
Account a = null;
a = Database.getInstance().getAccountByUserPw(acc);
return a;
}
Android Client:
public Account postData(String JSONtoSend)
{
URL url;
Account get = new Account();
try {
url = new URL("http://192.xxx.xxx.x:18080/HolidayOutServer/webresources/validateacc");
HttpURLConnection urlCon = (HttpURLConnection) url.openConnection();
urlCon.setRequestMethod("POST");
urlCon.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
urlCon.setRequestProperty("Accept", "application/json; charset=UTF-8");
urlCon.setDoOutput(true); // to be able to write.
urlCon.setDoInput(true); // to be able to read.
OutputStreamWriter out = new OutputStreamWriter(urlCon.getOutputStream());
out.write(JSONtoSend);
ObjectInputStream ois = new ObjectInputStream(urlCon.getInputStream());
get = (Account) ois.readObject();
return get;
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return get;
}
which is called within this:
class help extends AsyncTask<String, Void, Account>
{
#Override
protected Account doInBackground(String... params) {
return postData(new Gson().toJson(new Account("aleqs", "lexx", -2)));
}
}
Problems in a nutshell:
Jersey Server receives null
Android throws this ridiculous EOFException.
Can somebody help ?
Thanks in advance,
John.
Ok, I managed to find a solution here after hours.
This code works for me:
try( DataOutputStream wr = new DataOutputStream( urlCon.getOutputStream())) {
wr.write(new Gson().toJson(new Account("aleqs", "lexx", -2)).getBytes());
}
Reader in = new BufferedReader(new InputStreamReader(urlCon.getInputStream(), "UTF-8"));
StringBuilder sb = new StringBuilder();
for (int c; (c = in.read()) >= 0;)
sb.append((char)c);
response = sb.toString();
return response;
} catch (IOException e) {
e.printStackTrace();
}
return response;
Change the return type of "donInBackGround" to String and let the helper class extend -String, Void, String-.
MOST IMPORTANT: CHECK IF YOUR ATTRIBUTES ON CLIENT SIDE (eg. id, name, ..) match with those from SERVER SIDE.
Consider cap locks and so on..
Cheers !

Android HttpUrlConnection response object

Hey i'm using HttpUrlConnection in my app. And it's seems to me that every time when I'm making call as .getInputStream() or urlConnection.getResponseCode() etc it makes another request, so it is not good for me, when i'm making POST request. Is there a way to get some kind of response object which encapsulates response data and can be accessible from UI thread, something like this:
private class RegisterAsync extends AsyncTask<String, Void, HttpResponse> {
protected String doInBackground(String... strings) {
HttpURLConnection urlConnection = null;
String message = null;
try {
URL url = new URL(REGISTER_URL);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setDoOutput(true);
urlConnection.setChunkedStreamingMode(0);
OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
out.write(strings[0].getBytes("UTF-8"));
out.flush();
out.close();
HttpResponse response = urlConnection.getResponse();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
urlConnection.disconnect();
}
return Response;
}
protected void onPostExecute(HttpResponse response) {
//Do some with response object: get status, headers, content etc?
}
}
you can do the following steps:
Create the webservice call in a singleton class
Parse the response and encapsulate it in a custom object(made by you) and save the parsed object into the singleton as instance object.
After this, you can simply send a broadcast message to your activity to let it know that the parsed data is available in the singleton
the onReceive() method of BroadcastReceiver runs on UI thread so you can quickly update your UI there..
After you implement that you can simply call the singleton webservice call method from your activity right after you register to the intent that will be sent from the singleton...

HttpURLConnection.getResponseCode() freezes execution/doesn't time out

I'm writing an Android app that connects to a cPanel server (Apache 2.2.22) page which is password protected. When the authentication credentials are correct, I have no problem connecting. However, when the credentials are incorrect, my Android application seems to freeze in the HttpURLConnection.getResponseCode() method. The logs on the server show hundreds of requests being sent from my Android device, all returning a 401 as expected, but for some reason this is not reflected in my application.
Here is my code, executed from within an AsyncTask:
#Override
protected Integer doInBackground(String... bookInfoString) {
// Stop if cancelled
if(isCancelled()){
return null;
}
Log.i(getClass().getName(), "SendToDatabase.doInBackground()");
String apiUrlString = getResources().getString(R.string.url_vages_library);
try{
NetworkConnection connection = new NetworkConnection(apiUrlString);
connection.appendPostData(bookInfoString[0]);
int responseCode = connection.getResponseCode();
Log.d(getClass().getName(), "responseCode: " + responseCode);
return responseCode;
} catch(IOException e) {
return null;
}
}
This code makes use of my own class NetworkConnection, which is just a basic wrapper class around an HttpURLConnection, to avoid repeating code. Here it is:
public class NetworkConnection {
private String url;
private HttpURLConnection connection;
public NetworkConnection(String urlString) throws IOException{
Log.i(getClass().getName(), "Building NetworkConnection for the URL \"" + urlString + "\"");
url = urlString;
// Build Connection.
try{
URL url = new URL(urlString);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setReadTimeout(1000 /* 1 seconds */);
connection.setConnectTimeout(1000 /* 1 seconds */);
} catch (MalformedURLException e) {
// Impossible: The only two URLs used in the app are taken from string resources.
e.printStackTrace();
} catch (ProtocolException e) {
// Impossible: "GET" is a perfectly valid request method.
e.printStackTrace();
}
}
public void appendPostData(String postData) {
try{
Log.d(getClass().getName(), "appendPostData() called.\n" + postData);
Log.d(getClass().getName(), "connection.getConnectTimeout(): " + connection.getConnectTimeout());
Log.d(getClass().getName(), "connection.getReadTimeout(): " + connection.getReadTimeout());
// Modify connection settings.
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/json");
// Get OutputStream and attach POST data.
OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream(), "UTF-8");
writer.write(postData);
if(writer != null){
writer.flush();
writer.close();
}
} catch (SocketTimeoutException e) {
Log.w(getClass().getName(), "Connection timed out.");
} catch (ProtocolException e) {
// Impossible: "POST" is a perfectly valid request method.
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// Impossible: "UTF-8" is a perfectly valid encoding.
e.printStackTrace();
} catch (IOException e) {
// Pretty sure this is impossible but not 100%.
e.printStackTrace();
}
}
public int getResponseCode() throws IOException{
Log.i(getClass().getName(), "getResponseCode()");
int responseCode = connection.getResponseCode();
Log.i(getClass().getName(), "responseCode: " + responseCode);
return responseCode;
}
public void disconnect(){
Log.i(getClass().getName(), "disconnect()");
connection.disconnect();
}
}
And finally, here is a fraction of the logcat logs:
05-03 11:01:16.315: D/vages.library.NetworkConnection(3408): connection.getConnectTimeout(): 1000
05-03 11:01:16.315: D/vages.library.NetworkConnection(3408): connection.getReadTimeout(): 1000
05-03 11:01:16.585: I/vages.library.NetworkConnection(3408): getResponseCode()
05-03 11:04:06.395: I/vages.library.MainActivity$SendToDatabase(3408): SendToDatabase.onPostExecute(null)
You can see the the method seems to just return null after a random amount of time. The longest I have waited was exactly 15 minutes. There are also several memory logs (GC_CONCURRENT) from dalikvm between the last two info logs which I have omitted.
I should also say that at the moment I am not using https, although I do not believe that should cause any problems. I would be very grateful for any feedback with this, whether it's a complete answer or just a comment telling me what isn't the problem, as I am still unsure whether this problem is server-side or client-side.
Thank you very much,
William
EDIT: I forgot to mention before, I am attaching my authentication credentials with my own custom java.net.Authenticator:
public class CustomAuthenticator extends Authenticator {
Context mContext;
public CustomAuthenticator(Context context){
super();
mContext = context;
}
#Override
protected PasswordAuthentication getPasswordAuthentication() {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
String username = sharedPreferences.getString(SettingsActivity.KEY_USERNAME_PREFERENCE, null);
String password = sharedPreferences.getString(SettingsActivity.KEY_PASSWORD_PREFERENCE, null);
return new PasswordAuthentication(username, password.toCharArray());
}
}
which I set in the activity'sonCreate() method:
Authenticator.setDefault(new CustomAuthenticator(mContext));
Also, I have used curl to request the password protected resource, and have received a 401 as expected. I am now assuming the problem is client-side.
It seems to be an issue with using Authenticator in POST connections. It's quite old so I don't know if it still exists.
I would try two things:
Add a log line in the getPasswordAuthentication of the Authenticator to see if it's effectively called. If nothing is printed, you should check that you add the default Authenticator before it's called. You say you do it in the onCreate(), so it should be fine but it's good to be sure.
Avoid using the Authenticator (at least for testing purposes) and send the auth info directly in the HTTP Request. I usually do it this way:
String auth = user + ":" + pass;
conn = (HttpURLConnection) url.openConnection();
conn.setRequestProperty("Authorization",
"Basic " + Base64.encode(auth.getBytes()));
// Set other parameters and read the result...
The problem was that the 401 Unauthorized status is sent when the Authorization header is missing and when the credentials contained within the header are incorrect. Therefore, my app was constantly sending the same request over and over to no avail. I have therefore found a workaround to the problem by adding a counter into my CustomAuthenticator:
public class CustomAuthenticator extends Authenticator {
public static int RETRIES = 3;
int mRetriesLeft;
Context mContext;
public CustomAuthenticator(Context context){
super();
mRetriesLeft = RETRIES;
mContext = context;
}
#Override
protected PasswordAuthentication getPasswordAuthentication() {
Log.i(getClass().getName(), "getPasswordAuthentication() - mCounter: " + mRetriesLeft);
if(mRetriesLeft > 0){
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
String username = sharedPreferences.getString(SettingsActivity.KEY_USERNAME_PREFERENCE, null);
String password = sharedPreferences.getString(SettingsActivity.KEY_PASSWORD_PREFERENCE, null);
mRetriesLeft--;
return new PasswordAuthentication(username, password.toCharArray());
} else {
Log.w(getClass().getName(), "No more retries. Returning null");
mRetriesLeft = RETRIES;
return null;
}
}
public void reset(){
mRetriesLeft = RETRIES;
}
}
I should say however that I do not like this solution and therefore, have not accepted it. You have to remember to reset the counter whenever you make a new request (I do it in AsyncTask.onPreExecute()), or else every third request will fail. Also, I'm sure there must be a native way to do this, although after scouring the documentation I can't find it. I would still be very grateful if anyone can point it out to me.
I don't know if I am right or not but my solution has worked for me for a whole day without a glitch.
Try doing this
byte[] buf = new byte[4096];
Inputstream is;
do
{
http conn code etc;
is=conn.getInputStream();
if(is.read(buf)==0)
{
flag=1;
}
//u can either is.close(); or leave as is
//code
int serverResponseCode = connection.getResponseCode();
String serverResponseMessage = connection.getResponseMessage();
conn.disconnect();
} while(flag==1);

Categories

Resources