Vark Vark - 3 months ago 22
HTTP Question

Sending image file with retrofit 2

I am trying to upload an image to our project's server using Retrofit 2

The image is picked through an image picking activity and seems to work since the file (image) can be displayed using Picasso.

Retrofit succeeds however the server doesn't seem to get the file.
Here is the server side part.

func (c *gin.Context) {
file, header , err := c.Request.FormFile("profileImage")
// err = http: no such file
}


Sever side error message

Even the RequestBody prints coherent information when I tested it (size, image type...)

Service :

@Multipart
@PATCH("/user/profileImage")
Call<ResponseBody> modifyUserImage(@Part("profileImage") RequestBody profileImage, @Part("userID") RequestBody userID);


Following code is part of the same Fragment class

Opening image picking activity :

Intent getIntent = new Intent(Intent.ACTION_GET_CONTENT);
getIntent.setType("image/*");

Intent pickIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
pickIntent.setType("image/*");

Intent chooserIntent = Intent.createChooser(getIntent, "Select Image");
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[]{pickIntent});

startActivityForResult(chooserIntent, 1);


On Activity Result:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);

if (resultCode == Activity.RESULT_OK && requestCode == 1) {
// process the result
Uri selectedImage = data.getData();
String wholeID = DocumentsContract.getDocumentId(selectedImage);
String id = wholeID.split(":")[1];
String[] column = {MediaStore.Images.Media.DATA};
String sel = MediaStore.Images.Media._ID + "=?";
Cursor cursor = getActivity().getContentResolver().
query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
column, sel, new String[]{id}, null);
String filePath = "";
int columnIndex = cursor.getColumnIndex(column[0]);
if (cursor.moveToFirst()) {
filePath = cursor.getString(columnIndex);
}
cursor.close();

file = new File(filePath);
Picasso
.with(getActivity().getApplicationContext())
.load(file)
.into(civ_userProfilePicture);
}
}


Request :

Call<ResponseBody> call = ServiceSingelton.getmInstance().getService()
.modifyUserImage(RequestBody.create(MediaType.parse("image/*"), file),
RequestBody.create(MediaType.parse("text/plain"), ServiceSingelton.getmInstance().getUserID()));

call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.code() == 200) {
Log.d("RETROFIT SUCCESS", "Pic should be sent");
} else {
Log.d("RETROFIT SUCCESS", "Error code received modifying user");
}
}

@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d("RETROFIT ERROR", t.getMessage());
}
});

Answer

Someone gave me this fix which worked :

To post a part with filename, you should change @Part("profileImage") RequestBody profileImage to @Part RequestBody profileImage, and pass it MultipartBody.Part.createFormData(partName, filename, requestBody):

// Service
@Multipart
@PATCH("/user/profileImage")
Call<ResponseBody> modifyUserImage(@Part MultipartBody.Part profileImage, @Part("userID") RequestBody userID);

// Call
MultipartBody.Part imagePart = MultipartBody.Part.createFormData("profileImage", file.getName(), RequestBody.create(MediaType.parse("image/*"), file));
Call<ResponseBody> call = ServiceSingelton.getmInstance().getService()
                        .modifyUserImage(imagePart,
                                         RequestBody.create(MediaType.parse("text/plain"), ServiceSingelton.getmInstance().getUserID()));