I'm using volley library in android to call our server when try to send base64 encoded image to server the request fail but when remove the encoded string the request success without any issue.
I use the following code to encode my image
public static String imgToBase64(Bitmap bitmap) {
ByteArrayOutputStream out = null;
try {
out = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 50, out);
out.flush();
out.close();
byte[] imgBytes = out.toByteArray();
return Base64.encodeToString(imgBytes, Base64.DEFAULT);
} catch (Exception e) {
return null;
} finally {
try {
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
and send request using volley with the following
public void sendDataToServer(final ApiResponse.Listener<JSONObject> listener, final ApiResponse.ErrorListener errorListener, String image) {
String url = String.format(ASK, image);
url = URLEncoder.encode(url);
JsonRequest sendRequest = new JsonRequest(Request.Method.POST, url,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
listener.onResponse(response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
if (error != null) {
if (error.networkResponse != null) {
errorListener.onErrorResponse(error.networkResponse.statusCode, null);
} else {
errorListener.onErrorResponse(500, null);
}
}
}
});
RequestPipeline.getInstance(mContext).addToRequestQueue(sendRequest);
}
Looking into your code it looks like you try to pass whole encoded image as a part of URL. Obviously this fail because servers typically don't support URL longer than a few thousand of symbols. To pass long data to the server you should use body of the POST. I don't know what your JsonEmptyResponseRequest class is and what format the server expects (how ASK is specified). Just to give you an idea how this might be implemented
StringRequest sendRequest = new StringRequest(Request.Method.POST, url,
new Response.Listener ...,
new Response.ErrorListener...){
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put(IMAGE_PARAM_NAME, image);
return params;
}
};
In real life you probably want to create your own sub-class of Request<T> and pass image there as a constructor parameter and hide exactly details of what server expects inside that class. Note that JsonRequest overrides getBody and getBodyContentType to use JSON so this will not work with JsonRequest subclass.
Related
I am trying to create an app on android studio and im new to this IDE and language. I managed to implement the GET method for Imflip api, but im stuck on the POST method. I would like to return an Meme with a caption added by the user.
Im using Android Studio 3.4.1. I've tried the code attached. For testing purposes, i've hardcoded the username, password, and two captions. Also, when i call POST() I pass the id 61579 as a parameter. I've tried finding he value for the response but it says that its "200"...
What i need is a url for the created meme.
Hope anyone can help.
Thanks in Advance.
private void POST(String memeID) {
try {
RequestQueue requestQueue = Volley.newRequestQueue(this);
String URL = "https://api.imgflip.com/caption_image";
JSONObject jsonBody = new JSONObject();
jsonBody.put("template_id", memeID);
jsonBody.put("username", "Meme_Genie");
jsonBody.put("password", "Password");
jsonBody.put("text0", "Hello");
jsonBody.put("text1", "World");
final String requestBody = jsonBody.toString();
StringRequest stringRequest = new StringRequest(Request.Method.POST, URL, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.i("VOLLEY", response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("VOLLEY", error.toString());
}
}) {
#Override
public String getBodyContentType() {
return "application/json; charset=utf-8";
}
#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);
// can get more details such as response.headers
}
return Response.success(responseString, HttpHeaderParser.parseCacheHeaders(response));
}
};
requestQueue.add(stringRequest);
} catch (JSONException e) {
e.printStackTrace();
}
}
Switching from encode = "json" to encode = "form"
Or switching your body to BodySerializationMethod.UrlEncoded will work
Im having trouble getting the correct code to send submit a multipart form with a PDF included to google cloud print( the reason I'm not using the inbuilt intent in android is that you cant automatically select a printer it need to be done manually when using the intent)
I have been using Volley to submit it but I have been reading its not great with large files?
final RequestQueue queue = Volley1.getInstance(this).getRequestQueue();
String url3 = "https://www.google.com/cloudprint/submit";
final VolleyMultipartRequest multipartRequest = new VolleyMultipartRequest(Request.Method.POST, url3 ,new Response.Listener<NetworkResponse>() {
#Override
public void onResponse(NetworkResponse response) {
String resultResponse = new String(response.data);
Log.d("responseis",resultResponse);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
}
}){
#Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<>();
// the POST parameters:
params.put("redirect_uri", "xxxxx");
params.put("printerid","xxxxxx");
params.put("title", "result1.pdf");
params.put("contentType", "application/pdf");
params.put("ticket", "{\"print\":{},\"version\":\"1.0\"}");
params.put("hl", "en");
return params;
}
#Override
public Map getHeaders() throws AuthFailureError {
Map headers = new HashMap();
headers.put("Authorization", "OAuth"+" "+res);
headers.put("Content-Type", "multipart/form-data; boundary=__1466595844361__");
//headers.put("Content-Type","application/x-www-form-urlencoded");
//Logger.debugE(Constants.accesstoken, headers.toString());
return headers;
}
#Override
protected Map<String, DataPart> getByteData() {
Map<String, DataPart> params = new HashMap<>();
//String yourFilePath = Environment.getExternalStorageDirectory().getAbsolutePath()+ "/PDFs/result1.pdf";
String yourFilePath=Environment.getExternalStorageDirectory().getAbsolutePath()+ "/PDFs/result1.pdf";
File dir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS), "PDF_reader");
File text = new File(dir + File.separator + "test_r.pdf");
String input = text.getAbsolutePath();
byte[] data = new byte[(int) input.length()];
try {
//convert file into array of bytes
data = FileUtils.readFileToByteArray(text);
}catch(Exception e){
e.printStackTrace();
}
params.put("content", new DataPart("result1.pdf",data , "application/pdf"));
return params;
}
};
queue.add(multipartrequest);
After a lot of trial and error I ended up using OKHTTP library and I was successfully able to submit a print job to google cloud print using the API. It was a bit tricky to get the multipart form with the pdf file included but the correct working request is below. Obviously the token and printerid are retrieved in other requests and need to be added manually.
public void run() throws Exception {
//File directory
File dir = Environment.getExternalStorageDirectory();
File file = new File(dir, "PDFs/result1.pdf");
if(file.canRead()){
Log.d("file", "can read");
}else {Log.d("file","cant read");};
// Final request body
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("content","result1.pdf",RequestBody.create(MediaType.parse("application/pdf"), file))
.build();
//URL Parameters
HttpUrl url = new HttpUrl.Builder()
.scheme("https")
.host("www.google.com")
.addPathSegments("cloudprint/submit")
.addQueryParameter("printerid", "82d70sde-694b-3385-f263-164cb04320c3")
.build();
Request request = new Request.Builder()
.header("Authorization", "OAuth ya29.Cl0jAxDuQni_Dskz6Y2r-wRaJVMxEw8fy5hPNfAm02pDLnZc9HX-RfHpmMoS0OL-Wv_SKxBtYIwRK9jVpJDwl7Qs-RFt02Qc5Yoid4w1kV8b4vBIpcleIQ8lBEto")
.url(url)
.post(requestBody)
.build();
client.newCall(request)
.enqueue(new Callback() {
#Override
public void onFailure(final Call call, IOException e) {
// Error
runOnUiThread(new Runnable() {
#Override
public void run() {
// For the example, you can show an error dialog or a toast
// on the main UI thread
}
});
}
#Override
public void onResponse(Call call, final Response response) throws IOException {
String res = response.body().string();
// Do something with the response
}
});
}
Trying to use this "Words API" in an android application which only seems to accept requests using Unirest.
Request example for the definition of "incredible" (specified by api):
HttpResponse<JsonNode> response = Unirest.get("https://wordsapiv1.p.mashape.com/words/incredible/definitions")
.header("X-Mashape-Key", "**********apikey************")
.header("Accept", "application/json")
.asJson();
The trouble is implementing the unirest request with doInBackground in AsyncTask.
protected void OnPreExecute(){
json_url = "https://wordsapiv1.p.mashape.com/words/incredible/definitions";
//where does api key go?
}
protected String doInBackground(Void... params) {
try {
// unirest goes here but how?
URL url = new URL(json_url);
HttpURLConnection httpURLConnection = (HttpURLConnection)url.openConnection();
InputStream inputStream = httpURLConnection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder stringBuilder = new StringBuilder();
while ((JSON_STRING = bufferedReader.readLine()) !=null)
stringBuilder.append(JSON_STRING+"\n");
bufferedReader.close();
inputStream.close();
httpURLConnection.disconnect();
return stringBuilder.toString().trim();
}catch (MalformedURLException e){
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
Not sure exactly how to structure the request within doInBackground.
Is it possible to do this?
This code is not tested but to give you an idea on how you might solve this problem.
private class TastingUniRestAsync extends AsyncTask<String, Void, String> {
protected String doInBackground(String... urls) {
String pathToFile = urls[0];
String responseResult = "";
HttpResponse<JsonNode> response = Unirest.get(pathToFile)
.header("X-Mashape-Key", "**********apikey************")
.header("Accept", "application/json")
.asJson();
if(null != response){
//convert your response to the data type you want. Here I am using string
responseResult = //assign the manipulated Json string;
}
return responseResult
}
protected void onPostExecute(String responseResult){
// You can assign it to TextView widget for example
mTextView.setText(responseResult);
}
}
I think the better solution would be to use the Volley library. Take a look at my solution, don't forget to add a dependency: compile 'com.android.volley:volley:1.0.0'. If you need more information.
RequestQueue requestQueue = Volley.newRequestQueue(this);
String uri = Uri.parse("https://wordsapiv1.p.mashape.com/words/incredible/definitions")
.buildUpon()
.build().toString();
StringRequest stringRequest = new StringRequest(
Request.Method.GET, uri, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.d("VolleyResponse", "response: " + response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("VolleyError", error.toString());
}
}) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<>();
params.put("X-Mashape-Key", "<API_KEY>");
params.put("Accept", "text/plain");
return params;
}
};
requestQueue.add(stringRequest);
I want small example to send JSON object in POST request from android volley and it has to receive Java Restful Webservices
You can use the following working sample code. Hope this helps!
...
try {
RequestQueue queue = Volley.newRequestQueue(this);
jsonBody = new JSONObject();
jsonBody.put("Title", "VolleyApp Android Demo");
jsonBody.put("Author", "BNK");
jsonBody.put("Date", "2015/08/26");
requestBody = jsonBody.toString();
StringRequest stringRequest = new StringRequest(1, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
textView.setText(response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
textView.setText(error.toString());
}
}) {
#Override
public String getBodyContentType() {
return String.format("application/json; charset=utf-8");
}
#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;
}
}
};
queue.addToRequestQueue(stringRequest);
} catch (JSONException e) {
e.printStackTrace();
}
Moreover, can you clarify what does it has to receive Java Restful Webservices mean? My above request receives String value.
I'm attempting to do a PUT in x-www-form-urlencoded to a drupal table with Volley from my Android app. I'm try to send a 'type' and 'value', in the params and I get a 500 error. A basic StringRequest returns 404.
Here's my latest code. I've only found one or two entries that touch on the Volley Put. Any help would be appreciated. Have a great day.
private void postTestAnswerResult(String id, String answerResult) {
StringRequest req = null;
requestQueue = Volley.newRequestQueue(this);
final String baseURL = "http://blah.blah.com/api/answer/";
String URL = baseURL + id;
// Post params to be sent to the server
HashMap<String, String> params = new HashMap<String, String>();
params.put("Content-Type","application/x-www-form-urlencoded");
params.put("type", answerResult);
req = new StringRequest(Request.Method.PUT, URL,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
VolleyLog.v("Response:%n %s", response.toString());
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
try {
String responseBody = new String(
volleyError.networkResponse.data, "utf-8");
JSONObject jsonObject = new JSONObject(responseBody);
} catch (JSONException e) {
// Handle a malformed json response
} catch (UnsupportedEncodingException error) {
}
}
}
);
requestQueue.add(req);
}
In case you are still having problems with this, as #Meier points out in a comment above, you are not using the params variable, or rather you aren't using it correctly. The data doesn't get sent to the server, and the server is probably expecting the data resulting in the 500 error.
You need to override the getParams method of the StringRequest call in order to send the data. So, the following would be closer to getting the job done:
private void postTestAnswerResult(String id, String answerResult) {
StringRequest req = null;
requestQueue = Volley.newRequestQueue(this);
final String baseURL = "http://blah.blah.com/api/answer/";
String URL = baseURL + id;
req = new StringRequest(Request.Method.PUT, URL,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
VolleyLog.v("Response:%n %s", response.toString());
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
try {
String responseBody = new String(
volleyError.networkResponse.data, "utf-8");
JSONObject jsonObject = new JSONObject(responseBody);
} catch (JSONException e) {
// Handle a malformed json response
} catch (UnsupportedEncodingException error) {
}
}
}
) {
#Override
protected Map<String, String> getParams()
{
HashMap<String, String> params = new HashMap<String, String>();
// params.put("Content-Type","application/x-www-form-urlencoded"); This shouldn't be here. This is a HTTP header. If you want to specify header you should also override getHeaders.
params.put("type", answerResult);
return params;
}
};
requestQueue.add(req);
Browser don't ignore 500 errors. They very often show up as ugly messages in the browser window.