POST Multipart Form Data using Retrofit 2.0 including image
Asked Answered
T

14

202

I am trying to do a HTTP POST to server using Retrofit 2.0

MediaType MEDIA_TYPE_TEXT = MediaType.parse("text/plain");
MediaType MEDIA_TYPE_IMAGE = MediaType.parse("image/*");

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    imageBitmap.compress(Bitmap.CompressFormat.JPEG,90,byteArrayOutputStream);
profilePictureByte = byteArrayOutputStream.toByteArray();

Call<APIResults> call = ServiceAPI.updateProfile(
        RequestBody.create(MEDIA_TYPE_TEXT, emailString),
        RequestBody.create(MEDIA_TYPE_IMAGE, profilePictureByte));

call.enqueue();

The server returns an error saying the file is not valid.

This is weird because I have tried to upload the same file with the same format on iOS(using other library), but it uploads successfully.

I am wondering what is the proper way to upload an image using Retrofit 2.0?

Should I save it to disk first before uploading?

P.S.: I have used retrofit for other Multipart request that does not include image and they completed successfully. The problem is when I am trying to include a byte to the body.

Trixi answered 2/1, 2016 at 5:31 Comment(2)
P
210

I am highlighting the solution in both 1.9 and 2.0 since it is useful for some

In 1.9, I think the better solution is to save the file to disk and use it as Typed file like:

RetroFit 1.9

(I don't know about your server-side implementation) have an API interface method similar to this

@POST("/en/Api/Results/UploadFile")
void UploadFile(@Part("file") TypedFile file,
                @Part("folder") String folder,
                Callback<Response> callback);

And use it like

TypedFile file = new TypedFile("multipart/form-data",
                                       new File(path));

For RetroFit 2 Use the following method

RetroFit 2.0 ( This was a workaround for an issue in RetroFit 2 which is fixed now, for the correct method refer jimmy0251's answer)

API Interface:

public interface ApiInterface {

    @Multipart
    @POST("/api/Accounts/editaccount")
    Call<User> editUser(@Header("Authorization") String authorization,
                        @Part("file\"; filename=\"pp.png\" ") RequestBody file,
                        @Part("FirstName") RequestBody fname,
                        @Part("Id") RequestBody id);
}

Use it like:

File file = new File(imageUri.getPath());

RequestBody fbody = RequestBody.create(MediaType.parse("image/*"),
                                       file);

RequestBody name = RequestBody.create(MediaType.parse("text/plain"),
                                      firstNameField.getText()
                                                    .toString());

RequestBody id = RequestBody.create(MediaType.parse("text/plain"),
                                    AZUtils.getUserId(this));

Call<User> call = client.editUser(AZUtils.getToken(this),
                                  fbody,
                                  name,
                                  id);

call.enqueue(new Callback<User>() {

    @Override
    public void onResponse(retrofit.Response<User> response,
                           Retrofit retrofit) {

        AZUtils.printObject(response.body());
    }

    @Override
    public void onFailure(Throwable t) {

        t.printStackTrace();
    }
});
Pascoe answered 2/1, 2016 at 5:37 Comment(14)
TypedFile is not supported/included in Retrofit 2.0Trixi
Yes,well I think it is an issue (github.com/square/retrofit/issues/1063) with retrofit 2.0,you might wanna stick with 1.9Pascoe
Yes, that is why I am wondering if there is any other solution other than saving the byte to a File. Since it is an extra Permission needed and does not seem to be efficient, "performancely" speaking. Thanks for answering though.Trixi
see my edit ,I have not tryed it yet,you are welcomed toPascoe
I have decided to use the approach you posted. Thank youTrixi
Tried uploading image file using Retrofit 2.0 but it didn't work for me. Has anyone successfully uploaded file using Retrofit 2.0Aconcagua
I have successfylly uploaded an image using de Retrofit 2.0 example.Sacker
@Part("file\"; filename=\"pp.png\" ") I see the file name is hardcoded here, what if I want to the name to change?Aloin
@Aloin You can change the interface to @Multipart @POST("/api/Accounts/editaccount") Call<User> editUser(@PartMap Map<String, RequestBody> params); And When you have the file: Map<String, RequestBody> map = new HashMap<>(); RequestBody fileBody = RequestBody.create(MediaType.parse("image/jpg"), file); map.put("file\"; filename=\"" + file.getName(), fileBody);Pascoe
@Pascoe Yes I just found out about that, can also use MultiPartBody.PartAloin
You didn't explain your answer hereVanillin
What more explanation do you need Donato? The one who asked the question is familiar with Retrofit and satisfied with the answer so did other 86 people, What more do you need?Pascoe
This is a hack. It's been fixed in retrofit 2 for a long time by using MultipartBody.Part parameters in your retrofit service. See @Presentational answer belowShowdown
PayloadTooLargeError: request entity too largeLaise
P
226

There is a correct way of uploading a file with its name with Retrofit 2, without any hack:

Define API interface:

@Multipart
@POST("uploadAttachment")
Call<MyResponse> uploadAttachment(@Part MultipartBody.Part filePart); 
                                   // You can add other parameters too

Upload file like this:

File file = // initialize file here

MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", file.getName(), RequestBody.create(MediaType.parse("image/*"), file));

Call<MyResponse> call = api.uploadAttachment(filePart);

This demonstrates only file uploading, you can also add other parameters in the same method with @Part annotation.

Presentational answered 11/8, 2016 at 8:23 Comment(18)
how can we send multiple files using MultipartBody.Part?Sitter
You can use multiple MultipartBody.Part arguments in the same API.Presentational
I need to send collections of images with "image[]" as a key. I tried @Part("images[]") List<MultipartBody.Part> images but it gives error that @Part parameters using the MultipartBody.Part must not include a part nameSitter
You should use @Body MultipartBody multipartBody and MultipartBody.Builder for sending collection of images.Presentational
how i can added key to mutipartNewsprint
@Presentational hello I want to switch from Volley to Retrofit. What about audio and video. In Volley, we have this conversion of bytes... how about in Retrofit, how do you pass audio and video to server? Thanks a lot.Gomer
You can upload any file with the above method, just use appropriate mimetype of the File.Presentational
@Presentational can you please look at my question #44225688?Lafayette
This should be marked as the correct answer as it does the job with less and simpler code.Spectre
I'm still getting : {"statusCode":400,"field":"media","type":"isValidMime","error":"media - Unsopported file format","generatedError":"media - Unsopported file format"}Phonation
@Presentational getting error if i use chinease name for file.getfileName(), app getting crash showing error form-dataBondy
@Presentational can help me with this @Part("channel[comment][image]") . i have to upload image on this channel[comment][image] key . how can i do that.Sension
how do you initialize an image file with just the uri in your answer?Groats
receiving file type on server is image/* instead of image/jpg or image/png. etc..Exocentric
This is crucial, how do we use this with an images[] key?Subclavian
This is an extremely helpful answer! Can confirm the resulting form is parsed correctly by Flask.Allahabad
Using MediaType.parse(String): MediaType? is an error now. Replaced with String.toMediaTypeOrNull() extension function.Virelay
Also you can [or must] use File.asRequestBody(MediaType?) extension function instead of RequestBody.create(). (I'm using OkHttp v4.0.+ and Retrofit v2.9.+.)Virelay
P
210

I am highlighting the solution in both 1.9 and 2.0 since it is useful for some

In 1.9, I think the better solution is to save the file to disk and use it as Typed file like:

RetroFit 1.9

(I don't know about your server-side implementation) have an API interface method similar to this

@POST("/en/Api/Results/UploadFile")
void UploadFile(@Part("file") TypedFile file,
                @Part("folder") String folder,
                Callback<Response> callback);

And use it like

TypedFile file = new TypedFile("multipart/form-data",
                                       new File(path));

For RetroFit 2 Use the following method

RetroFit 2.0 ( This was a workaround for an issue in RetroFit 2 which is fixed now, for the correct method refer jimmy0251's answer)

API Interface:

public interface ApiInterface {

    @Multipart
    @POST("/api/Accounts/editaccount")
    Call<User> editUser(@Header("Authorization") String authorization,
                        @Part("file\"; filename=\"pp.png\" ") RequestBody file,
                        @Part("FirstName") RequestBody fname,
                        @Part("Id") RequestBody id);
}

Use it like:

File file = new File(imageUri.getPath());

RequestBody fbody = RequestBody.create(MediaType.parse("image/*"),
                                       file);

RequestBody name = RequestBody.create(MediaType.parse("text/plain"),
                                      firstNameField.getText()
                                                    .toString());

RequestBody id = RequestBody.create(MediaType.parse("text/plain"),
                                    AZUtils.getUserId(this));

Call<User> call = client.editUser(AZUtils.getToken(this),
                                  fbody,
                                  name,
                                  id);

call.enqueue(new Callback<User>() {

    @Override
    public void onResponse(retrofit.Response<User> response,
                           Retrofit retrofit) {

        AZUtils.printObject(response.body());
    }

    @Override
    public void onFailure(Throwable t) {

        t.printStackTrace();
    }
});
Pascoe answered 2/1, 2016 at 5:37 Comment(14)
TypedFile is not supported/included in Retrofit 2.0Trixi
Yes,well I think it is an issue (github.com/square/retrofit/issues/1063) with retrofit 2.0,you might wanna stick with 1.9Pascoe
Yes, that is why I am wondering if there is any other solution other than saving the byte to a File. Since it is an extra Permission needed and does not seem to be efficient, "performancely" speaking. Thanks for answering though.Trixi
see my edit ,I have not tryed it yet,you are welcomed toPascoe
I have decided to use the approach you posted. Thank youTrixi
Tried uploading image file using Retrofit 2.0 but it didn't work for me. Has anyone successfully uploaded file using Retrofit 2.0Aconcagua
I have successfylly uploaded an image using de Retrofit 2.0 example.Sacker
@Part("file\"; filename=\"pp.png\" ") I see the file name is hardcoded here, what if I want to the name to change?Aloin
@Aloin You can change the interface to @Multipart @POST("/api/Accounts/editaccount") Call<User> editUser(@PartMap Map<String, RequestBody> params); And When you have the file: Map<String, RequestBody> map = new HashMap<>(); RequestBody fileBody = RequestBody.create(MediaType.parse("image/jpg"), file); map.put("file\"; filename=\"" + file.getName(), fileBody);Pascoe
@Pascoe Yes I just found out about that, can also use MultiPartBody.PartAloin
You didn't explain your answer hereVanillin
What more explanation do you need Donato? The one who asked the question is familiar with Retrofit and satisfied with the answer so did other 86 people, What more do you need?Pascoe
This is a hack. It's been fixed in retrofit 2 for a long time by using MultipartBody.Part parameters in your retrofit service. See @Presentational answer belowShowdown
PayloadTooLargeError: request entity too largeLaise
C
25

I used Retrofit 2.0 for my register users, send multipart/form File image and text from register account

In my RegisterActivity, use an AsyncTask

//AsyncTask
private class Register extends AsyncTask<String, Void, String> {

    @Override
    protected void onPreExecute() {..}

    @Override
    protected String doInBackground(String... params) {
        new com.tequilasoft.mesasderegalos.dbo.Register().register(txtNombres, selectedImagePath, txtEmail, txtPassword);
        responseMensaje = StaticValues.mensaje ;
        mensajeCodigo = StaticValues.mensajeCodigo;
        return String.valueOf(StaticValues.code);
    }

    @Override
    protected void onPostExecute(String codeResult) {..}

And in my Register.java class is where use Retrofit with synchronous call

import android.util.Log;
import com.tequilasoft.mesasderegalos.interfaces.RegisterService;
import com.tequilasoft.mesasderegalos.utils.StaticValues;
import com.tequilasoft.mesasderegalos.utils.Utilities;
import java.io.File;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Call; 
import retrofit2.Response;
/**Created by sam on 2/09/16.*/
public class Register {

public void register(String nombres, String selectedImagePath, String email, String password){

    try {
        // create upload service client
        RegisterService service = ServiceGenerator.createUser(RegisterService.class);

        // add another part within the multipart request
        RequestBody requestEmail =
                RequestBody.create(
                        MediaType.parse("multipart/form-data"), email);
        // add another part within the multipart request
        RequestBody requestPassword =
                RequestBody.create(
                        MediaType.parse("multipart/form-data"), password);
        // add another part within the multipart request
        RequestBody requestNombres =
                RequestBody.create(
                        MediaType.parse("multipart/form-data"), nombres);

        MultipartBody.Part imagenPerfil = null;
        if(selectedImagePath!=null){
            File file = new File(selectedImagePath);
            Log.i("Register","Nombre del archivo "+file.getName());
            // create RequestBody instance from file
            RequestBody requestFile =
                    RequestBody.create(MediaType.parse("multipart/form-data"), file);
            // MultipartBody.Part is used to send also the actual file name
            imagenPerfil = MultipartBody.Part.createFormData("imagenPerfil", file.getName(), requestFile);
        }

        // finally, execute the request
        Call<ResponseBody> call = service.registerUser(imagenPerfil, requestEmail,requestPassword,requestNombres);
        Response<ResponseBody> bodyResponse = call.execute();
        StaticValues.code  = bodyResponse.code();
        StaticValues.mensaje  = bodyResponse.message();
        ResponseBody errorBody = bodyResponse.errorBody();
        StaticValues.mensajeCodigo  = errorBody==null
                ?null
                :Utilities.mensajeCodigoDeLaRespuestaJSON(bodyResponse.errorBody().byteStream());
        Log.i("Register","Code "+StaticValues.code);
        Log.i("Register","mensaje "+StaticValues.mensaje);
        Log.i("Register","mensajeCodigo "+StaticValues.mensaje);
    }
    catch (Exception e){
        e.printStackTrace();
    }
}
}

In the interface of RegisterService

public interface RegisterService {
@Multipart
@POST(StaticValues.REGISTER)
Call<ResponseBody> registerUser(@Part MultipartBody.Part image,
                                @Part("email") RequestBody email,
                                @Part("password") RequestBody password,
                                @Part("nombre") RequestBody nombre
);
}

For the Utilities parse ofr InputStream response

public class Utilities {
public static String mensajeCodigoDeLaRespuestaJSON(InputStream inputStream){
    String mensajeCodigo = null;
    try {
        BufferedReader reader = new BufferedReader(
                new InputStreamReader(
                    inputStream, "iso-8859-1"), 8);
        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            sb.append(line).append("\n");
        }
        inputStream.close();
        mensajeCodigo = sb.toString();
    } catch (Exception e) {
        Log.e("Buffer Error", "Error converting result " + e.toString());
    }
    return mensajeCodigo;
}
}
Closeup answered 6/10, 2016 at 16:57 Comment(0)
I
22

Update Code for image file uploading in Retrofit2.0

public interface ApiInterface {

    @Multipart
    @POST("user/signup")
    Call<UserModelResponse> updateProfilePhotoProcess(@Part("email") RequestBody email,
                                                      @Part("password") RequestBody password,
                                                      @Part("profile_pic\"; filename=\"pp.png")
                                                              RequestBody file);
}

Change MediaType.parse("image/*") to MediaType.parse("image/jpeg")

RequestBody reqFile = RequestBody.create(MediaType.parse("image/jpeg"),
                                         file);
RequestBody email = RequestBody.create(MediaType.parse("text/plain"),
                                       "[email protected]");
RequestBody password = RequestBody.create(MediaType.parse("text/plain"),
                                          "123456789");

Call<UserModelResponse> call = apiService.updateProfilePhotoProcess(email,
                                                                    password,
                                                                    reqFile);
call.enqueue(new Callback<UserModelResponse>() {

    @Override
    public void onResponse(Call<UserModelResponse> call,
                           Response<UserModelResponse> response) {

        String
                TAG =
                response.body()
                        .toString();

        UserModelResponse userModelResponse = response.body();
        UserModel userModel = userModelResponse.getUserModel();

        Log.d("MainActivity",
              "user image = " + userModel.getProfilePic());

    }

    @Override
    public void onFailure(Call<UserModelResponse> call,
                          Throwable t) {

        Toast.makeText(MainActivity.this,
                       "" + TAG,
                       Toast.LENGTH_LONG)
             .show();

    }
});
Icebreaker answered 6/8, 2016 at 5:44 Comment(4)
I was trying many ways to do this but I could not get the results. I just changed this ("Change MediaType.parse("image/*") to MediaType.parse("image/jpeg")") like you said and it works now, thank you so much.Coterie
wish i could give you more than one votes,Thank you.Nims
if your api has @Multipart then @Part annotation must supply a name or use MultipartBody.Part parameter type.Bernal
Good solution! And there's one more quote in @Part("profile_pic\"; filename=\"pp.png\" ", it shoule be @Part("profile_pic\"; filename=\"pp.png "Towers
M
21

So its very simple way to achieve your task. You need to follow below step :-

1. First step

public interface APIService {  
    @Multipart
    @POST("upload")
    Call<ResponseBody> upload(
        @Part("item") RequestBody description,
        @Part("imageNumber") RequestBody description,
        @Part MultipartBody.Part imageFile
    );
}

You need to make the entire call as @Multipart request. item and image number is just string body which is wrapped in RequestBody. We use the MultipartBody.Part class that allows us to send the actual file name besides the binary file data with the request

2. Second step

  File file = (File) params[0];
  RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);

  MultipartBody.Part body =MultipartBody.Part.createFormData("Image", file.getName(), requestBody);

  RequestBody ItemId = RequestBody.create(okhttp3.MultipartBody.FORM, "22");
  RequestBody ImageNumber = RequestBody.create(okhttp3.MultipartBody.FORM,"1");
  final Call<UploadImageResponse> request = apiService.uploadItemImage(body, ItemId,ImageNumber);

Now you have image path and you need to convert into file.Now convert file into RequestBody using method RequestBody.create(MediaType.parse("multipart/form-data"), file). Now you need to convert your RequestBody requestFile into MultipartBody.Part using method MultipartBody.Part.createFormData("Image", file.getName(), requestBody); .

ImageNumber and ItemId is my another data which I need to send to server so I am also make both thing into RequestBody.

For more info

Moll answered 12/5, 2018 at 19:52 Comment(0)
C
15

Adding to the answer given by @insomniac. You can create a Map to put the parameter for RequestBody including image.

Code for Interface

public interface ApiInterface {
@Multipart
@POST("/api/Accounts/editaccount")
Call<User> editUser (@Header("Authorization") String authorization, @PartMap Map<String, RequestBody> map);
}

Code for Java class

File file = new File(imageUri.getPath());
RequestBody fbody = RequestBody.create(MediaType.parse("image/*"), file);
RequestBody name = RequestBody.create(MediaType.parse("text/plain"), firstNameField.getText().toString());
RequestBody id = RequestBody.create(MediaType.parse("text/plain"), AZUtils.getUserId(this));

Map<String, RequestBody> map = new HashMap<>();
map.put("file\"; filename=\"pp.png\" ", fbody);
map.put("FirstName", name);
map.put("Id", id);
Call<User> call = client.editUser(AZUtils.getToken(this), map);
call.enqueue(new Callback<User>() {
@Override
public void onResponse(retrofit.Response<User> response, Retrofit retrofit) 
{
    AZUtils.printObject(response.body());
}

@Override
public void onFailure(Throwable t) {
    t.printStackTrace();
 }
});
Contrive answered 25/4, 2017 at 9:46 Comment(2)
how can i upload multiple files with 2 strings?Deodar
Is it possible for you to answer #60428738Darlinedarling
W
7

in kotlin its quite easy, using extensions methods of toMediaType, asRequestBody and toRequestBody here's an example:

here I am posting a couple of normal fields along with a pdf file and an image file using multipart

this is API declaration using retrofit:

    @Multipart
    @POST("api/Lesson/AddNewLesson")
    fun createLesson(
        @Part("userId") userId: RequestBody,
        @Part("LessonTitle") lessonTitle: RequestBody,
        @Part pdf: MultipartBody.Part,
        @Part imageFile: MultipartBody.Part
    ): Maybe<BaseResponse<String>>

and here is how to actually call it:

api.createLesson(
            userId.toRequestBody("text/plain".toMediaType()),
            lessonTitle.toRequestBody("text/plain".toMediaType()),
            startFromRegister.toString().toRequestBody("text/plain".toMediaType()),
            MultipartBody.Part.createFormData(
                "jpeg",
                imageFile.name,
                imageFile.asRequestBody("image/*".toMediaType())
            ),
            MultipartBody.Part.createFormData(
                "pdf",
                pdfFile.name,
                pdfFile.asRequestBody("application/pdf".toMediaType())
            )
Whist answered 10/5, 2020 at 11:59 Comment(1)
But what about the authentication / token ?Journey
D
4
* Return MultipartBody from file path

 public static MultipartBody.Part generateFileBody(String imagePath)
    {
        File file = new File(imagePath);
        RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);
        return MultipartBody.Part.createFormData("mediaProfilePic", file.getName(), requestFile);
    }
David answered 4/4, 2021 at 8:56 Comment(0)
R
3

Uploading Files using Retrofit is Quite Simple You need to build your api interface as

public interface Api {

    String BASE_URL = "http://192.168.43.124/ImageUploadApi/";


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

}

in the above code image is the key name so if you are using php you will write $_FILES['image']['tmp_name'] to get this. And filename="myfile.jpg" is the name of your file that is being sent with the request.

Now to upload the file you need a method that will give you the absolute path from the Uri.

private String getRealPathFromURI(Uri contentUri) {
    String[] proj = {MediaStore.Images.Media.DATA};
    CursorLoader loader = new CursorLoader(this, contentUri, proj, null, null, null);
    Cursor cursor = loader.loadInBackground();
    int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
    cursor.moveToFirst();
    String result = cursor.getString(column_index);
    cursor.close();
    return result;
}

Now you can use the below code to upload your file.

 private void uploadFile(Uri fileUri, String desc) {

        //creating a file
        File file = new File(getRealPathFromURI(fileUri));

        //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();
            }
        });
    }

For more detailed explanation you can visit this Retrofit Upload File Tutorial.

Righthander answered 5/10, 2017 at 11:29 Comment(1)
This is a hack, it's been fixed in retrofit 2.0 for awhile. See jimmy0251 answer below.Showdown
O
2

Kotlin version with update for deprication of RequestBody.create :

Retrofit interface

@Multipart
@POST("uploadPhoto")
fun uploadFile(@Part file: MultipartBody.Part): Call<FileResponse>

and to Upload

fun uploadFile(fileUrl: String){
    val file = File(fileUrl)
    val fileUploadService = RetrofitClientInstance.retrofitInstance.create(FileUploadService::class.java)
    val requestBody = file.asRequestBody(file.extension.toMediaTypeOrNull())
    val filePart = MultipartBody.Part.createFormData(
        "blob",file.name,requestBody
    )
    val call = fileUploadService.uploadFile(filePart)

    call.enqueue(object: Callback<FileResponse>{
        override fun onFailure(call: Call<FileResponse>, t: Throwable) {
            Log.d(TAG,"Fckd")
        }

        override fun onResponse(call: Call<FileResponse>, response: Response<FileResponse>) {
            Log.d(TAG,"success"+response.toString()+" "+response.body().toString()+"  "+response.body()?.status)
        }

    })
}

Thanks to @jimmy0251

Otter answered 23/10, 2019 at 7:11 Comment(0)
V
2

requestBody can used to upload

  val body: RequestBody = MultipartBody.Builder().setType(MultipartBody.FORM)
        .addFormDataPart(
            "file", "<image name you wish to give>",
            RequestBody.create(
                MediaType.parse("application/octet-stream"),
                File(path)
            )
        )
        .build()
uploadProfilePhoto(body)

then call like this :

   @POST("/**")
    suspend fun uploadProfilePhoto(
        @Body body: RequestBody,
    ): ResponseBody
}
Vernacularism answered 28/11, 2021 at 6:26 Comment(1)
Builder by okhttp3.MultipartBody.Builder() 👍🏼Declan
D
2

Create Interface

@Multipart
@POST("/upload-manager/api/v1/files/survey-uploads")
Call<JsonObject> uploadSurveyFiles(@Header("Authorization") String token,
                                   @Part("cmp_id") RequestBody campaignID,
                                   @Part MultipartBody.Part images);
}

Call Upload API

    MultipartBody.Part imageParts = null;
    RequestBody campaignID = RequestBody.create(MediaType.parse("text/plain"), surveyDataModel.getId() + "");
    imageParts = prepareFilePart(GEO_FENCE_KEY, Uri.parse(filee.getAbsolutePath()));
    APIService mApiService = ApiUtils.getApiService();
    mApiService.uploadSurveyFiles("bearer " + AppSessionManager.getUserDetails().get(AppSessionManager.USER_TOKEN),
            campaignID, imageParts).enqueue(new Callback<JsonObject>() {
        @Override
        public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {

            //populateDialog.dismiss();

            if (response.isSuccessful()) {
               Toasty.warning(context, "Success", Toast.LENGTH_SHORT).show();
            }
            } else {
              
                Toasty.warning(context, "Something went wrong!", Toast.LENGTH_SHORT).show();
            }
        }

        @Override
        public void onFailure(Call<JsonObject> call, Throwable t) {
          Toasty.warning(context, ""+t.getMessage(), Toast.LENGTH_SHORT).show();
        }
    });
Disentail answered 4/12, 2023 at 10:42 Comment(0)
A
0

Don't use multiple parameters in the function name just go with simple few args convention that will increase the readability of codes, for this you can do like -

// MultipartBody.Part.createFormData("partName", data)
Call<SomReponse> methodName(@Part MultiPartBody.Part part);
// RequestBody.create(MediaType.get("text/plain"), data)
Call<SomReponse> methodName(@Part(value = "partName") RequestBody part); 
/* for single use or you can use by Part name with Request body */

// add multiple list of part as abstraction |ease of readability|
Call<SomReponse> methodName(@Part List<MultiPartBody.Part> parts); 
Call<SomReponse> methodName(@PartMap Map<String, RequestBody> parts);
// this way you will save the abstraction of multiple parts.

There can be multiple exceptions that you may encounter while using Retrofit, all of the exceptions documented as code, have a walkthrough to retrofit2/RequestFactory.java. you can able to two functions parseParameterAnnotation and parseMethodAnnotation where you can able to exception thrown, please go through this, it will save your much of time than googling/stackoverflow

Apulia answered 15/3, 2020 at 18:36 Comment(0)
W
0

In my case, I needed to send a PDF file (application/pdf), along with JSON information (application/json). Thankfully, Retrofit2 makes this super simple.

My interface looks as follows:

interface MyApi {
    @Multipart
    @POST("upload")
    fun uploadPDF(
        @Part file: MultipartBody.Part,
        @Part(value = "jsoninfo") jsoninfo: MyJsonObject
    ): Call<MyResponse>
}

Where jsoninfo is the name of my JSON data, MyJsonObject is my data class, and MyResponse is the response I'm expecting, of course.

Then, I just call my API method as follows:

val myJsonObject = MyJsonObject(...)

// "file" is of type byte[] already
val requestBody = RequestBody.create(file, MediaType.parse("application/pdf"))
val filePart = MultipartBody.Part.createFormData("file", "myfile.pdf", requestBody)

api.uploadPDF(filePart, myJsonObject).enqueue(...)
Weird answered 28/1, 2022 at 7:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.