Anonymous upload to Imgur's API using Retrofit 2 - android

I let my user select a picture in their gallery, save its Uri, set a title and description and wish to upload it anonymously using Imgur's API, with this endpoint using Retrofit 2.
So far, this is what I am doing with no success:
In my ImgurAPI interface:
#Multipart
#POST("image")
Call<BrowseData> postImage(
#Header("Authorization") String auth,
#Part MultipartBody.Part file,
#Query("image") String image,
#Query("album") String albumId,
#Query("type") String type,
#Query("title") String title,
#Query("description") String description
);
In my API handler:
public void uploadImage(Uri fileUri, String image, String album, String type,
String title, String description) {
// create upload service client (retrofit builder and such)
ImgurAPI service =
ServiceGenerator.createService(ImgurAPI.class);
File file = FileUtils.getFile(caller.getActivity(), fileUri);
// create RequestBody instance from file
RequestBody requestFile =
RequestBody.create(
MediaType.parse(caller.getActivity().getContentResolver().getType(fileUri)),
file
);
// MultipartBody.Part is used to send also the actual file name
MultipartBody.Part body =
MultipartBody.Part.createFormData("picture", file.getName(), requestFile);
// finally, execute the request
Call<BrowseData> call = service.postImage(clientId, body, image, album, type, title, description);
call.enqueue(new Callback<BrowseData>() {
#Override
public void onResponse(Call<BrowseData> call,
Response<BrowseData> response) {
Log.v("Upload", "success");
}
#Override
public void onFailure(Call<BrowseData> call, Throwable t) {
Log.e("Upload error:", t.getMessage());
}
});
}
That is called like such on a simple FAB click:
controller = new ImgurAPIHandler(this);
controller.uploadImage(chosenUri, encodedImage, "AlbumName", "base64", title, desc);
But upon executing the request, I get the following error:
Write error: ssl=0x9c531200: I/O error during system call, Broken pipe
Can somebody explain to me what I am doing wrong? (If you have sufficient information).

Related

Android Studio - Using retrofit2 to get info from restdb

I'm trying to use Retrofit2 to create a GET petition for my Android app. I have followed a tutorial on how to create the code and it worked with a webpage that did not need any authentication. Then I tried to adapt the same code to my needs, but I can't get it right. Either I get a 401 error or I get a 500 error.
I want to reach this URL: http://adaptai-eea8.restdb.io/rest/usuarios
So my baseurl is http://adaptai-eea8.restdb.io/.
This is my function, which is in the MainActivity:
private void find(String codigo){
String apikey = "9dc3afb8b6087192d5e9e50c5f2cb44927be5";
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://adaptai-eea8.restdb.io/")
.addConverterFactory(GsonConverterFactory.create()).build();
UsuarioAPI usuarioAPI = retrofit.create(UsuarioAPI.class);
Call<Usuario> call = usuarioAPI.find(codigo);
call.enqueue(new Callback<Usuario>() {
#Override
public void onResponse(Call<Usuario> call, Response<Usuario> response) {
try {
int a = 5;
if(response.isSuccessful()){
Usuario u = response.body();
textView.setText(u.getContra());
Log.d("Funciona", u.getContra());
}
}catch(Exception ex){
Toast.makeText(MainActivity.this, ex.getMessage(), Toast.LENGTH_SHORT);
}
}
#Override
public void onFailure(Call<Usuario> call, Throwable t) {
Toast.makeText(MainActivity.this, "Error de conexión", Toast.LENGTH_SHORT);
}
});
}
And this is the GET petition I am using:
#Headers({"User-Agent: my-restdb-app","Content-Type: application/x-www-form-urlencoded", "x-apikey: heregoestheapikey", "Accept: application/json", "cache-control: no-cache"})
//#FormUrlEncoded
#GET("rest/usuarios/")
//public Call<Usuario> find(#Query("nombre") String nombre);
Call<Usuario> find(#Query("nombre") String nombre);
There has to be something wrong with this code, and maybe it is related to sending the apikey as a header, i don't know. Can someone tell me where am I wrong? Thanks in advance.
If you want to pass the apiKey as header you need to pass it as a parameter like you can see in the docs
#Headers({"User-Agent: my-restdb-app","Content-Type: application/x-www-form-urlencoded", "Accept: application/json", "cache-control: no-cache"})
#GET("rest/usuarios/")
Call<Usuario> find(#Header("x-apikey") String apiKey, #Query("nombre") String nombre);
Additionally, are you sure about the rest of parameters? Like User-Agent being "my-restdb-app" and query param name being "nombre"

Retrofit: Only #Query is working but #Field is not working

I am tried to insert the data using #Field and #Body with #POST but it generates "500 internal server error" and same code I tried with #GET and #Query then it works correct and data inserted successfully.
So is there any way to insert data using #Body or #Field to my asp.net web-site using web service web method.
Using #Body
#POST("/EducationApi.asmx/addEducationAPI")
public void addEducation(#Body Education education, Callback<Education> callback);
'''
Using #Field
'''
#FormUrlEncoded
#POST("/EducationApi.asmx/insertEducationAPI/")
public void insertEducationDetail(#Field("user_id") int user_id, #Field("degree_name") String degree_name, #Field("institute_name") String institute_name, #Field("board_university_name") String board_university_name, #Field("year_of_passing") int year_of_passing, #Field("percentage_cgpa") float percentage_cgpa, #Field("specialization") String specialization, Callback<Education> callback);
using #Query (This works proper)
#GET("/EducationApi.asmx/insertEducationAPI")
public void insertEducation(#Query("user_id") int user_id,#Query("degree_name") String degree_name, #Query("institute_name") String institute_name, #Query("board_university_name") String board_university_name,#Query("year_of_passing") int year_of_passing,#Query("percentage_cgpa") float percentage_cgpa,#Query("specialization") String specialization, Callback<Education> callback);
I want to use #Post to insert the record to my database
#FormUrlEncoded
#POST("/EducationApi.asmx/insertEducationAPI/")
public void insertEducationDetail(#Field("user_id") int user_id, #Field("degree_name") String degree_name, #Field("institute_name") String institute_name, #Field("board_university_name") String board_university_name, #Field("year_of_passing") int year_of_passing, #Field("percentage_cgpa") float percentage_cgpa, #Field("specialization") String specialization, Callback<Education> callback);
I have done a silly mistake with the above code. That's why it is not working so change the above code to below code
#FormUrlEncoded
#POST("/EducationApi.asmx/insertEducationAPI")
public void insertEducationDetail(#Field("user_id") int user_id, #Field("degree_name") String degree_name, #Field("institute_name") String institute_name, #Field("board_university_name") String board_university_name, #Field("year_of_passing") int year_of_passing, #Field("percentage_cgpa") float percentage_cgpa, #Field("specialization") String specialization, Callback<Education> callback);
Yes It is Possible to Send Data With Body. Inside Body You can send #Field and #query or Multi-part Data as per Your Choice.
See Below Code Here I create On Class which merge #Field and Multi-part data for image upload and send all this data through Body.
public void addConactList(String name, String vessel, String email, String phone, String country, String note, String selectedfilename, ByteArrayOutputStream bos, String bvalue, String pvalue, String intrested) {
RetroFitService retroFitService = RetrofitClient.getSalesLead();
MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
builder.addFormDataPart(Const.Name, name)
.addFormDataPart(Const.Vessel, vessel)
.addFormDataPart(Const.Email, email)
.addFormDataPart(Const.Phone, phone)
.addFormDataPart(Const.Country, country)
.addFormDataPart(Const.Notes, note)
.addFormDataPart(Const.Photo, selectedfilename, RequestBody.create(MultipartBody.FORM, bos.toByteArray()))
.addFormDataPart(Const.Business, bvalue)
.addFormDataPart(Const.Probability, pvalue)
.addFormDataPart(Const.Interest, intrested);
RequestBody requestBody = builder.build();
try {
Call<ContactResponse> call = retroFitService.addCountryList(requestBody);
call.enqueue(new Callback<ContactResponse>() {
#Override
public void onResponse(Call<ContactResponse> call, Response<ContactResponse> response) {
ContactResponse msg = response.body();
Log.e(TAG, "onResponse: " + msg.toString());
listener.onAddContact();
}
#Override
public void onFailure(Call<ContactResponse> call, Throwable t) {
Log.e(TAG, "onFailure: " + t.toString());
listener.onAddContact();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
Then after i call this class file Method from my activity using Below Code.
new AddContactDetails(context, this).addConactList(name, vessel, email, phone, country, note, selectedFileName, bos, bvalue, pvalue, intrested);
You Have to Post body method in Retrofit Service Class like below code.
#POST(Const.Add_Contact)
Call<ContactResponse> addCountryList(#Body RequestBody file);

How to retrieve image from a JSON Response from API using retrofit

I'm getting a JSON response where it shows my image path but i can't just directly load the image from it's path using retrofit.
Here's the JSON Output sample:
{
"Emp_Photo": "/Images/2018_07_02_05_30_24.jpg",
}
I tried fetching and storing the value of Emp_Photo into a string and loaded the string into imageview using picasso but it doesn't work.
Here's some part of my code which i'm trying to accomplish:
final ProgressDialog progressDialog = new ProgressDialog(getActivity());
progressDialog.setMessage("Fetching Data...");
progressDialog.show();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(ApiClient.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
Fetchemployeedetailsinterface service = retrofit.create(Fetchemployeedetailsinterface.class);
//Result is our pojo class
SharedPreferences settings = getActivity().getSharedPreferences("PREFS_NAME", 0);
String emailtoken= settings.getString("email", "").toString();
Call<ResponseData> call = service.Bind_Employee_Details_Based_On_Id(emailtoken);
call.enqueue(new Callback<ResponseData>() {
#Override
public void onResponse(Call<ResponseData> call, Response<ResponseData> response) {
//.getMessage is POJO method to listen for final json output
List<MessageItem> listResponse =response.body().getMessage();
String fname=listResponse.get(0).getEmpFirstName();
String lname=listResponse.get(0).getEmpLastName();
String email=listResponse.get(0).getEmpEmail();
String address=listResponse.get(0).getEmpAddress();
String joindt=listResponse.get(0).getJoiningDate();
String imgaddress=listResponse.get(0).getEmpPhoto();
Picasso.with(getActivity()).load(imgaddress).into(pick);
ettvname.setText(fname+"-"+lname);
etfname.setText(fname);
etlname.setText(lname);
etemail.setText(email);
etaddress.setText(address);
etjoindt.setText(joindt);
progressDialog.dismiss();
}
#Override
public void onFailure(Call<ResponseData> call, Throwable t) {
progressDialog.dismiss();
Toast.makeText(getActivity(), t.getMessage(), Toast.LENGTH_LONG).show();
}
});
Your Emp_Photo is just the path of the image. You should convert it to a full URL, then load it with Picasso.
String imageUrl = YOUR_ROOT_IMAGE + imgaddress
Picasso.with(getActivity()).load(imageUrl).into(pick);
Other advice:
And you should apply some conventions to make your code easier to read.
service.Bind_Employee_Details_Based_On_Id() -> service.bindEmployeeDetailsBasedOnId()
Fetchemployeedetailsinterface -> FetchEmployeeDetailsInterface
...
And here:
List<MessageItem> listResponse =response.body().getMessage();
String fname=listResponse.get(0).getEmpFirstName();
You should check and make sure listResponse has at least 1 item to prevent your app crash at runtime.
As you have mentioned in your description you are getting the only path of the image. But, you are not getting the full path of your image. So, you should have to required fill path of your image from where you can fetch image and load in your image view easily. For that you have to follow below method:
String image = base_URL + imgaddress; //Here base URL means initial path of your image or server.
Picasso.with(getActivity()).load(imgaddress).into(pick);
Try to get base_URL in response or another way.

Received Multipart File by Spring is null

I have a File and i want to send it to Spring Backend from Android. After receiving the image at Spring I am changing the name of the Image by Generating the UUID and then uploading it to AWS S3. My problem is i am getting null value as response.
Android Side ->
My Android Upload File Function ->
private void UploadFiles() {
File uploadFile = fileArrayList.get(0);
if (uploadFile != null) {
Log.d(TAG, "UploadFiles: File Name is -> " + uploadFile.getName());
// cropImageRequest.setCropId(uploadFile.getParentFile().getName());
// Parsing any Media type file
RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), uploadFile);
// MultipartBody.Part is used to send also the actual file name
MultipartBody.Part cropImage = MultipartBody.Part.createFormData("cropImage", uploadFile.getName(), requestFile);
Api.uploadCropImage(cropImage, new Callback<BasicResponse>() {
#Override
public void onResponse(Call<BasicResponse> call, Response<BasicResponse> response) {
if (response.body() != null) {
Log.d(TAG, "onResponse: Success" + response.body().getResponse());
}
else{
Log.d(TAG, "onResponse: null Response");
}
}
#Override
public void onFailure(Call<BasicResponse> call, Throwable t) {
Log.d(TAG, "onResponse: Failure");
}
});
}
}
**uploadImageFunction -> **
public static void uploadCropImage(MultipartBody.Part cropImage, Callback<BasicResponse> callback) {
UploadCropImageApi uploadCropImageApi = retrofit.create(UploadCropImageApi.class);
Call<BasicResponse> call = uploadCropImageApi.uploadCropImage(cropImage);
call.enqueue(callback);
}
My Interface ->
public interface UploadCropImageApi {
#Multipart
#POST(UPLOAD_FILE_TO_AWS_URL)
Call<BasicResponse> uploadCropImage(#Part MultipartBody.Part cropImage);
}
This is my Spring File ->
#RequestMapping(value = "/UploadCropImage", method = RequestMethod.POST, consumes = {"multipart/form-data"})
#ResponseBody
public String UploadImage(#RequestBody MultipartFile cropImage,HttpServletRequest request) {
mAmazonClient = AmazonClient.GetAmazonClientInstance();
UUIDUtils uuid = new UUIDUtils();
try {
System.out.println(cropImage);
String KeyName = uuid.GenerateUUID(cropImage.getName());
String Code = mAmazonClient.uploadImage(KeyName, cropImage);
System.out.println(Code);
return Code;
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println(e.getMessage());
return null;
}
}
This Controller is printing following value ->
org.springframework.web.multipart.commons.CommonsMultipartFile#b0b5de0
File Name is -: cropImage
null
My Problem is that as you can see the file sent by Retrofit and received by Spring is not null, I am sending that file via AWS, but it's not uploading the file and returns null as value. But when i use POSTMAN it's easily sending the file to AWS and returns the KeyName.
Okay so i debug a little bit and found out an exception while uploading Image file. and the exception is this -> The filename, directory name, or volume label syntax is incorrect.
Your exception says there is something wrong in your file name. The problem is naming convention as it was uploading file name containing ":" sign and there may be other signs as well which is not accepted by AWS. so, just change file name and separate the names by _(Underscore) sign instead of " "(space), (:) and other signs. This will successfully upload the file to the AWS. Hope it helps.

Image uploading Android + Sails.js

What are the possible ways/libraries available to upload images from android app to sails.js Node.js server?
One way that I came across to achieve this is sending Base64 encoded Bitmap image string from the app and saving it to the database, but this seems to be an inefficient way to handle multiple big size images as Base64 encoded string is 33% larger than raw size.
Another way is to send images as multipart form data, but I couldn't found good examples on this. Please, provide examples which demonstrate how to send images from app and handle it at serverside (node.js/sails.js)
Are there any other recommended libraries available to handle image uploading in android?
I use Multer to handle file uploads via multipart form data.
Out of the box it can do memory and disk storage. By using plugin modules you can use Multer to send files direct to S3 or other storage providers.
For backend level, use this piece of code in your SailsJS application:
uploadPhoto: function (req, res) {
req.file('photo').upload({
adapter: require('skipper-s3'),
key: S3_KEY,
secret: S3_SECRET,
bucket: IMAGE_BUCKET_NAME,
dirname: DIRECTORY_NAME,
region: S3_REGION
}, function (err, uploaded) {
if(err) {
//Image not uploaded
//Returned with error
} else if(uploaded.length == 0) {
//Image not uploaded
} else {
//Image uploaded
//Returned Image Path
var imagePath = uploaded[0].extra.Location;
}
});
},
And you need to send the file using multipart request. I am doing it with retrofit library. Here is the android code:
1. Create Multipart RequestBody Object
RequestBody file =
RequestBody.create(MediaType.parse("multipart/form-data"), photo); //photo is of type "File"
2. Handling RequestBody in Interface
#Multipart
#POST("api/uploadphoto")
Call<ResponseBody> uploadPhoto(#Part("photo\"; filename=\"pp\"") RequestBody file);
3. Then initiating the call to server
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Response<ResponseBody> response, Retrofit retrofit) {
Log.e("RESPONSE", response.body());
}
}
#Override
public void onFailure(Throwable t) {
Log.e("UploadPhoto", "failed");
}
});
That will upload the image to S3-Bucket.
Sails.js Backend file upload code and file will be uploaded in assets/images folder
upload: function (req, res) {
if (req.method === 'GET')
return res.json({
'status': 'GET not allowed'
});
// Call to /upload via GET is error
var data = req.file('uploadFile');
data.upload({
dirname: '../../assets/images'
}, function onUploadComplete(err, files) {
// Earlier it was ./assets/images .. Changed to ../../assets/images
// Files will be uploaded to ./assets/images
// Access it via localhost:1337/images/file-name
console.log(files);
if (err) {
console.log(err);
return res.json(500, err);
} else if (files.length === 0) {
// proceed without files
res.notFound({
status: 'Unsucess',
response: 'File not Uploaded'
});
} else {
// handle uploaded file
res.json({
status: 200,
file: files
});
}
});
}
Android Code :-
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("fileUploadType", "1")
.addFormDataPart("miniType", contentType)
.addFormDataPart("ext", file.getAbsolutePath().substring(file.getAbsolutePath().lastIndexOf(".")))
.addFormDataPart("fileTypeName", "img")
.addFormDataPart("clientFilePath", selectedImageUri.getPath())
.addFormDataPart("filedata", filename + ".png", fileBody)
.build();
Request request = new Request.Builder()
.url(API_URL)
.post(requestBody)
.build();
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, final IOException e) {
runOnUiThread(new Runnable() {
#Override
public void run() {
et_response.setText(e.getMessage());
Toast.makeText(MainActivity.this, "nah", Toast.LENGTH_SHORT).show();
}
});
}
#Override
public void onResponse(Call call, final Response response) throws IOException {
runOnUiThread(new Runnable() {
#Override
public void run() {
try {
et_response.setText(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
Toast.makeText(MainActivity.this, "response: " + response, Toast.LENGTH_LONG).show();
}
});
}
});
For Android Code You can Refer to
http://blog.aimanbaharum.com/2016/03/26/android-image-multi-part-upload/

Categories

Resources