94

I have an image of postman like below. How can I do the same thing in Retrofit 2?

Enter image description here

I've declared the interface like this:

@Multipart
@POST("/api/Pharmarcy/UploadImage")
Call<ResponseBody> uploadPrescriptionImage(
        @Query("accessToken") String token,
        @Query("pharmarcyRequestId") int pharmacyRequestedId,
        @Part MultipartBody.Part image);
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Azlan Jamal
  • 2,660
  • 3
  • 22
  • 29

8 Answers8

196
@Multipart
@POST("user/updateprofile")
Observable<ResponseBody> updateProfile(@Part("user_id") RequestBody id,
                                       @Part("full_name") RequestBody fullName,
                                       @Part MultipartBody.Part image,
                                       @Part("other") RequestBody other);

//pass it like this
File file = new File("/storage/emulated/0/Download/Corrections 6.jpg");
RequestBody requestFile =
        RequestBody.create(MediaType.parse("multipart/form-data"), file);

// MultipartBody.Part is used to send also the actual file name
MultipartBody.Part body =
        MultipartBody.Part.createFormData("image", file.getName(), requestFile);

// add another part within the multipart request
RequestBody fullName = 
        RequestBody.create(MediaType.parse("multipart/form-data"), "Your Name");

service.updateProfile(id, fullName, body, other);

Look at the way I am passing the multipart and string params. Hope this will help you!

tir38
  • 9,810
  • 10
  • 64
  • 107
android_griezmann
  • 3,757
  • 4
  • 16
  • 43
  • Can you please explain what is the "user_id", "full_name" and "other"? Is it possible to update your answer based on the question params? – Ultimo_m Jan 26 '18 at 15:54
  • 3
    @Ultimo_m These are the API request parameters. – android_griezmann Jan 29 '18 at 07:33
  • That day I had a problem (which in the end wasnt related to this thread) and I was looking at the postman photo and the only parameter in body is image, meanwhile you have also "RequestBody fullName" I thought that maybe there was smth I wasnt aware of. Thanks anyway for your replay:) – Ultimo_m Jan 29 '18 at 11:18
  • 1
    @android_griezmann I just have to pass an image to the api using multipart,how to do that ? – Neha Oct 01 '18 at 11:40
  • @Neha you can still refer to above code and pass only multi-part argument! – android_griezmann Oct 02 '18 at 04:59
  • @android_griezmann, can you look into this problem as well? I have used your code, but i am not getting images and other passed values. https://stackoverflow.com/questions/53343332/send-image-file-via-retrofit-from-android-to-spring/53343958?noredirect=1#comment93567802_53343958 – Avi Patel Nov 16 '18 at 19:52
  • @android_griezmann, is it possible to send multiparts, by generating one POJO class? I mean sending all variables by creatting one POJO? – Avi Patel Nov 18 '18 at 17:22
  • 1
    @AviPatel I have not familiar with passing the POJO class, but I guess if request's content-type is "Application/JSON" than you can pass the POJO. – android_griezmann Nov 19 '18 at 05:42
  • 1
    i got this error /storage/emulated/0/CinHindi.pdf: open failed: ENOENT (No such file or directory)\ – Infusion Analysts Apr 19 '19 at 08:26
  • how to handle this request in server side – Shikhar Aug 09 '19 at 05:16
  • why creating RequestBody for String??? `@Part("description") String description, @Part(value = "image", encoding = "8-bit") RequestBody image);` – user25 Nov 09 '20 at 16:57
  • @android_griezmann May I know why "Your Name" is required to be sent as RequestBody? – Tarun Anchala Jan 20 '21 at 12:27
  • Great answer. Also a note: When using ```@Part``` for something other than ```MultiBody.Part```, it will NOT work. Example: This will not work - ```Call uploadImage(@Part UploadBody body, @Part MultipartBody.Part image);```. You need the parameters ```Call uploadImage(@Part("user_data") UploadBody body, @Part MultipartBody.Part image);``` for it to work. – DIRTY DAVE Apr 06 '21 at 06:36
  • service.updateProfile(id, fullName, body, other); this line is giving error – Raghib Arshi Apr 15 '21 at 06:48
20

For those with an inputStream, you can upload inputStream using Multipart.

@Multipart
@POST("pictures")
suspend fun uploadPicture(
        @Part part: MultipartBody.Part
): NetworkPicture

Then in perhaps your repository class:

suspend fun upload(inputStream: InputStream) {
   val part = MultipartBody.Part.createFormData(
         "pic", "myPic", RequestBody.create(
              MediaType.parse("image/*"),
              inputStream.readBytes()
          )
   )
   uploadPicture(part)
}

If your backend does not allow multipart, you can convert the input stream into bytes and send the byte array as the request body, like so.

// In your service
 @PUT
 suspend fun s3Upload(
     @Header("Content-Type") mime: String,
     @Url uploadUrl: String, 
     @Body body: RequestBody 
 )
// In your repository
val body = RequestBody.create(MediaType.parse("application/octet"), inputStream.readBytes())
networkService.s3Upload(mime, url, body)

To get an input stream you can do something like so.

In your fragment or activity, you need to create an image picker that returns an InputStream. The advantage of an InputStream is that it can be used for files on the cloud like google drive and dropbox.

Call pickImagesLauncher.launch("image/*") from a View.OnClickListener or onOptionsItemSelected. (See Activity Result APIs).

private val pickImagesLauncher =
           registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
                uri?.let {
                    val stream = contentResolver.openInputStream(it)
                    itemViewModel.uploadPicture(stream)
                }
            }

override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)

      btn.setOnClickListener {
         pickImagesLauncher.launch("image/*")
     }
 }

Gilbert
  • 2,699
  • 28
  • 29
  • How to create an `InputStream` from `imageUri: Uri` – binrebin May 04 '20 at 17:58
  • @binrebin I have finished updating the answer to including creating an InputStream – Gilbert May 04 '20 at 21:03
  • If we perform `readBytes` without mentioning the size, isn't that will load the entire file content into memory, and cause OutOfMemory exception? – Cheok Yan Cheng May 16 '21 at 04:09
  • I suppose that could happen but I suspect only inn very rare circumstances like a phone with low RAM or a video file upload. In such cases, its the correct behaviour to crash. The application should not try to go around low resources, let it crash in such circumstances – GilbertS May 17 '21 at 05:46
  • @CheokYanCheng please see comment by GilbertS – Gilbert May 18 '21 at 03:04
  • 1
    This APIs like `onActivityResult` are deprecated. It's better to use new API called `ActivityResultContract` and `registerForActivityResult()`. – Mohsents Aug 10 '21 at 12:14
  • @Mohsents Good point! Can you kindly provide an edit to my answer – Gilbert Aug 11 '21 at 01:59
  • 2
    @Mohsents I tried registerForActivityResult in a Compose-only app and I can't recommend it. You end up with some awkward code. Stick with onActivityResult if you plan on doing a Compose-only app. – Johann Jan 18 '22 at 08:05
  • @Johann Thanks for your suggestion, I still haven't tried this APIs in compose but i'm sure they fix this issues. – Mohsents Jan 18 '22 at 14:02
  • Amazing !! this should be the accepted answer now as of Android 13 will provide only URI for image files – Onirban Sep 27 '22 at 15:28
9

Upload Image See Here click This Linkenter image description here

import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

class AppConfig {

    private static String BASE_URL = "http://mushtaq.16mb.com/";
    
    static Retrofit getRetrofit() {

        return new Retrofit.Builder()
                .baseUrl(AppConfig.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
    }
}

========================================================
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import retrofit2.Call;
import retrofit2.http.Multipart;
import retrofit2.http.POST;
import retrofit2.http.Part;

interface ApiConfig {
    @Multipart
    @POST("retrofit_example/upload_image.php")
    Call<ServerResponse> uploadFile(@Part MultipartBody.Part file,
                                    @Part("file") RequestBody name);

    /*@Multipart
    @POST("ImageUpload")
    Call<ServerResponseKeshav> uploadFile(@Part MultipartBody.Part file,
                                    @Part("file") RequestBody name);*/

    @Multipart
    @POST("retrofit_example/upload_multiple_files.php")
    Call<ServerResponse> uploadMulFile(@Part MultipartBody.Part file1,
                                       @Part MultipartBody.Part file2);
}
Joaquin Iurchuk
  • 5,499
  • 2
  • 48
  • 64
Keshav Gera
  • 10,807
  • 1
  • 75
  • 53
  • can you please share key for request parameters Am getting this error in postman
    Warning: move_uploaded_file(): Unable to move '/tmp/phpbhv7zZ' to 'uploads/device-2018-07-24-132846.png' in /home/u511106771/public_html/retrofit_example/upload_image.php on line 12
    {"success":false,"message":"Error while uploading"}
    – Patel Jaimin Oct 24 '18 at 13:52
8

I totally agree with @tir38 and @android_griezmann. This would be the version in Kotlin:

interface servicesEndPoint {
@Multipart
@POST("user/updateprofile")
fun updateProfile(@Part("user_id") id:RequestBody, @Part("full_name") fullName:RequestBody, @Part image: MultipartBody.Part, @Part("other") other:RequestBody): Single<UploadPhotoResponse>

companion object {
        val API_BASE_URL = "YOUR_URL"

        fun create(): servicesPhotoEndPoint {
            val retrofit = Retrofit.Builder()
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl(API_BASE_URL)
                .build()
            return retrofit.create(servicesPhotoEndPoint::class.java)
        }
    }
}

// Pass it like this
val file = File(RealPathUtils.getRealPathFromURI_API19(context, uri))
val requestFile: RequestBody = RequestBody.create(MediaType.parse("multipart/form-data"), file)

// MultipartBody.Part is used to send also the actual file name
val body: MultipartBody.Part = MultipartBody.Part.createFormData("image", file.name, requestFile)

// Add another part within the multipart request
val fullName: RequestBody = RequestBody.create(MediaType.parse("multipart/form-data"), "Your Name")

servicesEndPoint.create().updateProfile(id, fullName, body, fullName)

To obtain the real path, use RealPathUtils. Check this class in the answers of @Harsh Bhavsar in this question: How to get the Full file path from URI.

To getRealPathFromURI_API19, you need permissions of READ_EXTERNAL_STORAGE.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Fahed Hermoza
  • 343
  • 3
  • 11
2

Using Retrofit 2.0 you may use this:

@Multipart
    @POST("uploadImage")
    Call<ResponseBody> uploadImage(@Part("file\"; fileName=\"myFile.png\" ")RequestBody requestBodyFile, @Part("image") RequestBody requestBodyJson);

Make a request:

File imgFile = new File("YOUR IMAGE FILE PATH");
RequestBody requestBodyFile = RequestBody.create(MediaType.parse("image/*"), imgFile);
RequestBody requestBodyJson = RequestBody.create(MediaType.parse("text/plain"),
                    retrofitClient.getJsonObject(uploadRequest));



//make sync call
Call<ResponseBody> uploadBundle = uploadImpl.uploadImage(requestBodyFile, requestBodyJson);
Response<BaseResponse> response = uploadBundle.execute();

please refer https://square.github.io/retrofit/

Deepak
  • 33
  • 8
2
@Multipart
@POST(Config.UPLOAD_IMAGE)
Observable<Response<String>> uploadPhoto(@Header("Access-Token") String header, @Part MultipartBody.Part imageFile);

And you can call this api like this:

   public void uploadImage(File file) {
     // create multipart
     RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);
    MultipartBody.Part body = MultipartBody.Part.createFormData("image", file.getName(), requestFile);

    // upload
    getViewInteractor().showProfileUploadingProgress();

    Observable<Response<String>> observable = api.uploadPhoto("",body);

    // on Response
    subscribeForNetwork(observable, new ApiObserver<Response<String>>() {
        @Override
        public void onError(Throwable e) {
            getViewInteractor().hideProfileUploadingProgress();
        }

        @Override
        public void onResponse(Response<String> response) {

            if (response.code() != 200) {
                Timber.d("error " + response.code());
                return;
            }
            getViewInteractor().hideProfileUploadingProgress();
            getViewInteractor().onProfileImageUploadSuccess(response.body());

        }
    });

}
iamdeowanshi
  • 1,039
  • 11
  • 19
2

Retrofit 2.0 solution

@Multipart
@POST(APIUtils.UPDATE_PROFILE_IMAGE_URL)
public Call<CommonResponse> requestUpdateImage(@PartMap Map<String, RequestBody> map);

and

    Map<String, RequestBody> params = new HashMap<>();

    params.put("newProfilePicture" + "\"; filename=\"" + FilenameUtils.getName(file.getAbsolutePath()), RequestBody.create(MediaType.parse("image/jpg"), file));



 Call<CommonResponse> call = request.requestUpdateImage(params);

you can use
image/jpg image/png image/gif

adnan javed
  • 1,338
  • 8
  • 10
1

It is quite easy. Here is the API Interface

public interface Api {

    @Multipart
    @POST("upload")
    Call<MyResponse> uploadImage(@Part("image\"; filename=\"myfile.jpg\" ") RequestBody file, @Part("desc") RequestBody desc);

}

And you can use the following code to make a call.

private void uploadFile(File file, String desc) {

        //creating request body for file
        RequestBody requestFile = RequestBody.create(MediaType.parse(getContentResolver().getType(fileUri)), file);
        RequestBody descBody = RequestBody.create(MediaType.parse("text/plain"), desc);

        //The gson builder
        Gson gson = new GsonBuilder()
                .setLenient()
                .create();


        //creating retrofit object
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(Api.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create(gson))
                .build();

        //creating our api 
        Api api = retrofit.create(Api.class);

        //creating a call and calling the upload image method 
        Call<MyResponse> call = api.uploadImage(requestFile, descBody);

        //finally performing the call 
        call.enqueue(new Callback<MyResponse>() {
            @Override
            public void onResponse(Call<MyResponse> call, Response<MyResponse> response) {
                if (!response.body().error) {
                    Toast.makeText(getApplicationContext(), "File Uploaded Successfully...", Toast.LENGTH_LONG).show();
                } else {
                    Toast.makeText(getApplicationContext(), "Some error occurred...", Toast.LENGTH_LONG).show();
                }
            }

            @Override
            public void onFailure(Call<MyResponse> call, Throwable t) {
                Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_LONG).show();
            }
        });
    }

Source: Retrofit Upload File Tutorial.

Belal Khan
  • 2,099
  • 2
  • 22
  • 32