Skip to content Skip to sidebar Skip to footer

Retrofit 2 Can't Upload A File With Two Additional Separate String Parameters

Read edit at bottom of the question for possible alternative solution until the solution is found. This is a successful post file with two parameters using POSTMan. I am trying to

Solution 1:

I faced similar issue here: Android with Retrofit2 OkHttp3 - Multipart POST Error

I got my problem solved after taking @TommySM suggestion. If is still unclear to you, I think this is the solution:

@Multipart@POST("jobDocuments/upload")
Call<ResponseBody> upload(
    @Part MultipartBody.Part file,
    @Part("folder") RequestBody folder,
    @Part("name")   RequestBody name);

Filefile=newFile(fileUri.getPath());

// Assume your file is PNGRequestBodyrequestFile=
        RequestBody.create(MediaType.parse("image/png"), file);

MultipartBody.PartfileData=
        MultipartBody.Part.createFormData("file", fileName, requestFile);

RequestBodyfolder= RequestBody.create(
        MediaType.parse("text/plain"),
        "LeadDocuments");

RequestBodyname= RequestBody.create(
        MediaType.parse("text/plain"),
        fileName);

// finally, execute the request
Call<ResponseBody> call = service.upload(fileData, folder, name);

The important part is to use MediaType.parse("text/plain") for MediaType of String parameter (I believe your case is: folder & name parameter), using okhttp3.MultipartBody.FORM is a mistake.

See these screenshots for the comparison:

1) Problematic POST

enter image description here

2) Correct POST

enter image description here

Solution 2:

So, hope it's no too late, and if so - it might help somebody else :) my 2 cents about this is after having the same problem a while back:

The service definition, using @Part only (modify field names according to what your server expects)

//Single image MultiPart@Multipart@POST("user/imageupload")
Call<ResponseBody> upload(@Part("userfile") RequestBody file, @Part("userid") RequestBody description);

And for the magic trick, I refer to both parts just as RequestBody, using the MediaType.parse() to each one with it's own type, relying on the @Multipart definition for the request itself, no need for form-data stuff, the same works for multiple files, and multiple fields:

privatestatic final StringIMG_JPEG = "image/jpeg";
privatestatic final StringTXT_PLAIN = "text/plain";

publicvoiduploadImageMultipart(Uri uri, final CustomEventListener<String> listener)
{
    RequestBody fileBody;
    RequestBody textBody;
    File file = newFile(uri.getPath());
    Call<ResponseBody> requestCall;

    fileBody = RequestBody.create(okhttp3.MediaType.parse(IMG_JPEG), file);
    textBody = RequestBody.create(okhttp3.MediaType.parse(TXT_PLAIN), String.valueOf(SettingsManager.getUserID()));

      requestCall = serviceCaller.upload(fileBody, textBody);
      requestCall.enqueue(newCallback<ResponseBody>()
      {
        @OverridepublicvoidonResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> rawResponse)
        {
            try
            {
                String response = rawResponse.body().string();
                //from here it's your show....
                listener.getResult("Got it");
            }
            catch (Exception e)
            {
                        e.printStackTrace();
            }
        }

        @OverridepublicvoidonFailure(Call<ResponseBody> call, Throwable throwable)
        {

        }
    });
}

(I use a listener to return the callback response to a different part of the app (e.g. a calling activity)).

This definitely sends the file/s and the text field, other problems would probably stem from the server side.

Hope this Helps!

Solution 3:

Interface for Retrofit (API)

publicinterfaceAPI {

    StringNAME="name";
    StringFOLDER="folder";
    @Multipart@POST("/api/jobDocuments/upload")
    Call<JsonResponse> uploadFile(
        @Part(NAME) String name,
        @Part(FOLDER) String folder,
        @Part MultipartBody.Part file);
}

Response Class (JsonResponse)

publicclassJsonResponse{

    @SerializedName("$id")public String id;
    @SerializedName("Message")public String message;
    @SerializedName("Path")public String path;

    public JsonResponse(String id, String message, String path) {
        this.id = id;
        this.message = message;
        this.path = path;
    }
}

API call from application

Retrofit retrofit;

privatevoidpostImage() {
    StringURL="http://www.dgheating.com/";

    //your file locationFilefile=newFile(Environment.getExternalStorageDirectory() + "/Image.png");

    //parametersStringNAME= file.getName();
    StringFOLDER="LeadDocuments";
    StringFILE="file";

    retrofit = newRetrofit.Builder()
            .baseUrl(URL)
            .addConverterFactory(GsonConverterFactory.create(newGson()))
            .build();
    APIapi= retrofit.create(API.class);
    RequestBodyrequestBody= RequestBody.create(MediaType.parse("multipart/form-data"), file);
    MultipartBody.Partpart= MultipartBody.Part.createFormData(FILE, NAME, requestBody);
    Call<JsonResponse> call = api.uploadFile(NAME, FOLDER, part);

    call.enqueue(newCallback<JsonResponse>() {
        @OverridepublicvoidonResponse(Call<JsonResponse> call, Response<JsonResponse> response) {
            //response.body()           null//response.code()           500//https://github.com/square/retrofit/issues/1321
            Converter<ResponseBody, JsonResponse> errorConverter
                    = retrofit.responseBodyConverter(JsonResponse.class, newAnnotation[0]);
            try {
                JsonResponsejsonResponse= errorConverter.convert(response.errorBody());
                Log.e("error", "id:" + jsonResponse.id);                //1
                Log.e("error", "message:" + jsonResponse.message);      //An error has occurred
                Log.e("error", "path:" + jsonResponse.path);             //null
            } catch (IOException ignored) {
            }
        }

        @OverridepublicvoidonFailure(Call<JsonResponse> call, Throwable t) {

        }
    });
}

Error in fields, because of any of these server issue

  1. Google
  2. HTTP 500 response using retrofit, but Post request through Postman gives desired response
  3. How to get response body to retrofit exception?
  4. Retrofit SocketTimeoutException (and/or http 500 error) on http-POST

Solution 4:

It looks like your service definition is wrong. Try

@Multipart@POST("jobDocuments/upload")
Call<ResponseBody> upload(@Part("file") MultipartBody.Part file,@Part("folder") RequestBody folder,@Part("name") RequestBody name);

and

RequestBodyfolder=
        RequestBody.create(
                MediaType.parse("multipart/form-data"), "LeadDocuments");
RequestBodyname=
        RequestBody.create(
                MediaType.parse("multipart/form-data"), filename);   

in your @Background method. This all assumes you are using Retrofit2.

Post a Comment for "Retrofit 2 Can't Upload A File With Two Additional Separate String Parameters"