New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to Upload a File using Retrofit 2.0 #1063

Closed
vivekkiran opened this Issue Sep 7, 2015 · 98 comments

Comments

@vivekkiran
Copy link

vivekkiran commented Sep 7, 2015

How to upload a file using multipart/form-data upload in Retrofit 2.0, I am unable to upload and there is no proper documentation anywhere on uploading file using retrofit 2.0, I followed the docs in retrofit website but I was not able to make it work.

All the examples I see used TypedFile. It is not clear how to use RequestBody. Please post sample code.

@JakeWharton

This comment has been minimized.

Copy link
Collaborator

JakeWharton commented Sep 7, 2015

Same as v1. Use the Multipart annotation on the method and Part annotation
on parameters.

On Mon, Sep 7, 2015, 7:06 AM Vivek Kiran notifications@github.com wrote:

How to upload a file using multipart upload in Retrofit 2.0


Reply to this email directly or view it on GitHub
#1063.

@JakeWharton

This comment has been minimized.

Copy link
Collaborator

JakeWharton commented Sep 7, 2015

Oh for the file itself, use RequestBody for the type.

On Mon, Sep 7, 2015, 10:50 AM Jake Wharton jakewharton@gmail.com wrote:

Same as v1. Use the Multipart annotation on the method and Part annotation
on parameters.

On Mon, Sep 7, 2015, 7:06 AM Vivek Kiran notifications@github.com wrote:

How to upload a file using multipart upload in Retrofit 2.0


Reply to this email directly or view it on GitHub
#1063.

@VadimWelldone

This comment has been minimized.

Copy link

VadimWelldone commented Sep 7, 2015

Hi,

I am getting following exception while executing:

@Headers("User-Agent: " + Constants.CLIENT_NAME)
@Multipart
@POST(Constants.Urls.SYNC_URL)
Call<BaseResponseDto> uploadFile(@Part("file") RequestBody song, @Part("file_path") String fileName, @Part("method") String method, @Part("user_id") String userId, @Part("token") String token);

09-07 17:49:38.072 13562-13582/? W/EGL_emulation﹕ eglSurfaceAttrib not implemented

java.lang.IllegalStateException: JSON must start with an array or an object.
at com.google.gson.stream.JsonWriter.beforeValue(JsonWriter.java:609)
at com.google.gson.stream.JsonWriter.value(JsonWriter.java:418)
at com.google.gson.internal.bind.TypeAdapters$13.write(TypeAdapters.java:362)
at com.google.gson.internal.bind.TypeAdapters$13.write(TypeAdapters.java:346)
at com.google.gson.TypeAdapter.toJson(TypeAdapter.java:142)
at retrofit.GsonConverter.toBody(GsonConverter.java:55)
at retrofit.RequestBuilderAction$Part.perform(RequestBuilderAction.java:204)
at retrofit.RequestFactory.create(RequestFactory.java:62)
at retrofit.OkHttpCall.createRawCall(OkHttpCall.java:116)
at retrofit.OkHttpCall.execute(OkHttpCall.java:106)
at retrofit.ExecutorCallAdapterFactory$ExecutorCallbackCall.execute(ExecutorCallAdapterFactory.java:59)
at com.ibroadcast.mediasynclite.api.upload.UploadRunnable.run(UploadRunnable.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)

Everything worked until I migrated to Retrofit 2.0. Is anything wrong with my request?

Thanks in advance.

@JakeWharton

This comment has been minimized.

Copy link
Collaborator

JakeWharton commented Sep 7, 2015

Retrofit 2 is not released so I'll assume you mean the beta1. This is
already fixed in master and will be in the next release.

On Mon, Sep 7, 2015, 6:06 PM Vadim Oleynik notifications@github.com wrote:

Hi,

I am getting following exception while executing:

@headers("User-Agent: " + Constants.CLIENT_NAME)
@multipart
@post(Constants.Urls.SYNC_URL)
Call uploadFile(@part("file") RequestBody song, @part("file_path") String fileName, @part("method") String method, @part("user_id") String userId, @part("token") String token);

09-07 17:49:38.072 13562-13582/? W/EGL_emulation﹕ eglSurfaceAttrib not
implemented

java.lang.IllegalStateException: JSON must start with an array or an
object.
at com.google.gson.stream.JsonWriter.beforeValue(JsonWriter.java:609)
at com.google.gson.stream.JsonWriter.value(JsonWriter.java:418)
at
com.google.gson.internal.bind.TypeAdapters$13.write(TypeAdapters.java:362)
at
com.google.gson.internal.bind.TypeAdapters$13.write(TypeAdapters.java:346)
at com.google.gson.TypeAdapter.toJson(TypeAdapter.java:142)
at retrofit.GsonConverter.toBody(GsonConverter.java:55)
at
retrofit.RequestBuilderAction$Part.perform(RequestBuilderAction.java:204)
at retrofit.RequestFactory.create(RequestFactory.java:62)
at retrofit.OkHttpCall.createRawCall(OkHttpCall.java:116)
at retrofit.OkHttpCall.execute(OkHttpCall.java:106)
at
retrofit.ExecutorCallAdapterFactory$ExecutorCallbackCall.execute(ExecutorCallAdapterFactory.java:59)
at
com.ibroadcast.mediasynclite.api.upload.UploadRunnable.run(UploadRunnable.java:49)
at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)

Everything worked until I migrated to Retrofit 2.0. Is anything wrong with
my request?

Thanks in advance.


Reply to this email directly or view it on GitHub
#1063 (comment).

@JakeWharton

This comment has been minimized.

Copy link
Collaborator

JakeWharton commented Sep 7, 2015

Use the latest snapshot for the fix, or wait until the next release.

@JakeWharton JakeWharton closed this Sep 7, 2015

@VadimWelldone

This comment has been minimized.

Copy link

VadimWelldone commented Sep 8, 2015

Actually, I have downloaded the latest version using:

  1. maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
  2. compile 'com.squareup.retrofit:retrofit:2.0.0-SNAPSHOT'
  3. gradle clean
  4. rebuild project

But issue still exists :(

On Mon, Sep 7, 2015 at 7:25 PM, Jake Wharton notifications@github.com
wrote:

Closed #1063 #1063.


Reply to this email directly or view it on GitHub
#1063 (comment).

@ACzChef

This comment has been minimized.

Copy link

ACzChef commented Sep 10, 2015

I have also tried the same as VadimWelldone, and experienced no change or fix of the problem.

Edit: After some messing around this seems to be a problem with multi parts and not the use of RequestBody's

@VadimWelldone

This comment has been minimized.

Copy link

VadimWelldone commented Sep 15, 2015

Thanks Ashig. I'll try it a little bit later. Hope your approach will
resolve existing issue.

On Mon, Sep 14, 2015, 7:30 AM Ashiq Uz Zoha notifications@github.com
wrote:

I have a tested solution about this issue. You'll need to send to all
parameters as RequestBody.

@multipart
@post("/api/Accounts/addaccount")
Call signup(
@part("FirstName") RequestBody fname,
@part("LastName") RequestBody lname,
@part("email") RequestBody email,
@part("password") RequestBody password,
@part("username") RequestBody uname,
@part("Newsletter") RequestBody nl
);

And we need to call the method like this...

Call call = client.signup(
RequestBody.create(MediaType.parse("text"),firstNameField.getText().toString().getBytes()),
RequestBody.create(MediaType.parse("text"), lastNameField.getText().toString().getBytes()),
RequestBody.create(MediaType.parse("text"), emailField.getText().toString().getBytes()),
RequestBody.create(MediaType.parse("text"), passwordField.getText().toString().getBytes()),
RequestBody.create(MediaType.parse("text"), userNameField.getText().toString().getBytes()),
RequestBody.create(MediaType.parse("text"), toByteArray(bits))
);

Hope it helps.


Reply to this email directly or view it on GitHub
#1063 (comment).

@ayon115

This comment has been minimized.

Copy link

ayon115 commented Sep 15, 2015

Hello @VadimWelldone , I deleted that comment because after spending some more time, I noticed that for doing that approach I get status code 200 as response (may be because of my backend) but those parameters don't actually gets stored to my database correctly. So, thats not actually a solution.

But here is my real finding why. I am almost sure that, the Multipart request (file upload) is from okhttp. Retrofit probably has nothing to do with it. My Multipart request has both text and image data. When I pack all my text data into a PartMap and use @PartMap in Retrofit, these things gets Posted to backend correctly.

But there's problem with image or file upload. Retrofit 2.0 tells to use okhttp RequestBody to send file. I tried that both with Retrofit and Standalone okhttp library. None of my attempt could successfully upload the file to backend. So, I guess, this problem is from okhttp and we know Retrofit 2.0 uses it as default client. And I confirm that my API is fine as I can POST image and texts in single Multipart request with Android Volley.

@jimxj

This comment has been minimized.

Copy link

jimxj commented Sep 15, 2015

I had problem to upload file using Retrofit 2.0-SNAPSHOT before and found out the multipart format is not compatible with my server which accepts multipart/form-data. Here is my fix : jimxj@b44ab36

@wKovacs64

This comment has been minimized.

Copy link

wKovacs64 commented Sep 24, 2015

Still getting java.lang.IllegalStateException: JSON must start with an array or an object. from Gson when trying to post a multipart request where one of the parts is a file.

Retrofit 1.9.0 (using OkHttp 2.5.0):

    @Multipart
    @POST("/image/upload")
    Observable<UploadImageResponse>
    uploadImage(@Header(HEADER_AUTH_KEY) String token,
                @Part("userId") String userId,
                @Part("images") TypedFile file);

Where the file parameter is constructed as follows:

TypedFile file = new TypedFile("image/*", new File(path));

Retrofit 2.0.0-SNAPSHOT:

    @Multipart
    @POST("image/upload")
    Observable<UploadImageResponse>
    uploadImage(@Header(HEADER_AUTH_KEY) String token,
                @Part("userId") String userId,
                @Part("images") RequestBody file);

Where the file parameter is constructed as follows:

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

Am I doing something incorrectly, or is this not the same thing that @JakeWharton said was fixed in master? Did you get it to work, @VadimWelldone?

I did notice Gson can serialize TypedFile to JSON, but trying the same thing on RequestBody returns null. Related? I might be barking up the wrong tree here.

@tevjef

This comment has been minimized.

Copy link

tevjef commented Sep 25, 2015

A fixed was recently merged #1092 (comment). Is it already in the snapshot?

@JakeWharton

This comment has been minimized.

Copy link
Collaborator

JakeWharton commented Sep 25, 2015

snapshots are automatically deployed

On Thu, Sep 24, 2015 at 10:27 PM Tevin Jeffrey notifications@github.com
wrote:

A fixed was recently merged #1092 (comment)
#1092 (comment). Is it
already in the snapshot?


Reply to this email directly or view it on GitHub
#1063 (comment).

@VadimWelldone

This comment has been minimized.

Copy link

VadimWelldone commented Sep 25, 2015

@wKovacs64 It's very sad but I didn't manage to get it to work. I have rolled back to Retrofit 1.9.0 and continued to use it. Time frames was crucial for me and I chose working solution.

@waleoyediran

This comment has been minimized.

Copy link

waleoyediran commented Sep 28, 2015

Possibly related @VadimWelldone issue
I'm using 2.0.0-beta2.
and using the converter GsonConverterFactory

It seem it was serializing the file as a Form Field instead of a File Field

Debugging from a Python(Flask) server showed that

print request.form
print request.files

ImmutableMultiDict([('file-field', u'/PATH/TO/FILE/FILE-NAME.jpg'), ('field', u'"value"')])
ImmutableMultiDict([])

rather than

ImmutableMultiDict([('field', value')])
ImmutableMultiDict([('file-field', <FileStorage: u'FILE-NAME.jpg' ('image/jpeg')>)])
@wKovacs64

This comment has been minimized.

Copy link

wKovacs64 commented Sep 28, 2015

2.0.0-beta2 got me past the JSON problem (not sure why the snapshot didn't help). Now investigating the lack of filename key in the Content-Disposition header field, as mentioned in #1096 (comment) and the second half of #1130.

Do you have the headers from that request, @waleoyediran? I'm assuming yours must've included the filename somehow if you're seeing it on the web server like that.

@ayon115

This comment has been minimized.

Copy link

ayon115 commented Sep 30, 2015

I just tested with the method commented in #1140 and confirm that it works correctly. I am able to upload file in Multipart Request successfully. Sample code is below

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

"file" within @part annotation is the name of the file parameter and "filename" is the name of the file that's going to be uploaded.

I executed the above request like this...

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

Hope it helps.

@sungjin0213

This comment has been minimized.

Copy link

sungjin0213 commented Sep 30, 2015

@ayon115 Thank you so much. It really helped.

@mengoni

This comment has been minimized.

Copy link

mengoni commented Oct 6, 2015

@ayon115 Thanks, it works! But how to specify a dynamic filename in the interface (or in the RequestBody)?

@ayon115

This comment has been minimized.

Copy link

ayon115 commented Oct 6, 2015

@mengoni , I think we can't specify dynamic filename in the interface right now. As far I know, it's probably okhttp matter. I am using @PartMap to avoid hard-coding filename with Interface method. You can see the following example that might be useful.

 @Multipart
 @POST ("/api/Events/editevent")
 Call<Event> editEvent (@PartMap Map<String, RequestBody> params);

I call it by following way.

Map<String, RequestBody> map = new HashMap<>();
map.put("Id", AZUtils.toRequestBody(eventId));
map.put("Name", AZUtils.toRequestBody(titleView.getValue()));

if (imageUri != null) {
      File file = new File(imageUri.getPath());
      RequestBody fileBody = RequestBody.create(MediaType.parse("image/png"), file);
      map.put("file\"; filename=\"pp.png\"", fileBody);
}

Call<Event> call = api.editEvent(map);
call.enqueue(new Callback<Event>() { }

The method toRequestBody just converts String into RequestBody

 public static RequestBody toRequestBody (String value) {
        RequestBody body = RequestBody.create(MediaType.parse("text/plain"), value);
        return body ;
    }
@mhousser

This comment has been minimized.

Copy link

mhousser commented Oct 19, 2015

@ayon115 saved me as well. After upgrading from 1.9, in which I effortlessly uploaded image files with a @Multipart endpoint and a TypedFile attribute, the only thing I could do in Retrofit 2.0 was this ugly guy:

@Part("image\"; filename=\"image.jpg\" ") RequestBody image,

It works. This, unfortunately, does not work, as the back end can not find a FILE param named 'image':

@Part("image") RequestBody image,
@wKovacs64

This comment has been minimized.

Copy link

wKovacs64 commented Oct 19, 2015

@mhousser The way forward is being discussed/tracked in #1140. I have a PR in to essentially bring back a version of the old TypedFile API, if that interests you. The end result would look something like this:

File file = /* ... */;
TypedFile image = new TypedFile("image/png", file);

// ...

@PartFile("image") TypedFile image

...which should look familiar.

@mhousser

This comment has been minimized.

Copy link

mhousser commented Oct 19, 2015

Thanks!

@Part("image\"; filename=\"image.jpg\" ") RequestBody image

Is pretty hideous, but it works for now. I can hard-code the filename because I don't actually pay attention to it or use it server-side. (I hope this doesn't cause conflicts between different users uploading with the same filename..?)

@abcdeiko

This comment has been minimized.

Copy link

abcdeiko commented Oct 26, 2015

Is anybody know how i can show progress when i'm uploading a file?

@scognito

This comment has been minimized.

Copy link

scognito commented Apr 14, 2016

I confirm @jemshit solution is the only one that worked for me, thanks!

@lectricas

This comment has been minimized.

Copy link

lectricas commented Apr 21, 2016

Why retrofit developers cannot just create nice and smooth HOWTO? Make some code samples... Why everyone has to be a damn investigator to make everything works? Can't they just understand that if we are here, then the problem still exists? Have to wait for weeks to get any response on Stackoverflow.

Btw, I have "BAD REQUEST' with @jemshit method.

Map<String, RequestBody> requestDataMap = new HashMap<>();
        RequestBody userName = RequestBody.create(MediaType.parse("text/plain"), name.getText().toString());
        RequestBody userSecondName = RequestBody.create(MediaType.parse("text/plain"), lastName.getText().toString());
        RequestBody userEmail = RequestBody.create(MediaType.parse("text/plain"), email.getText().toString());
        RequestBody userPassword = RequestBody.create(MediaType.parse("text/plain"), PasswordUtils.encodePassword(encodePassword()));
        RequestBody userGender = RequestBody.create(MediaType.parse("text/plain"), male.isChecked() ? EmailProfile.GENDER_MALE : EmailProfile.GENDER_FEMALE);
        RequestBody avatar = RequestBody.create(MediaType.parse("image/jpg"), avatarPath);

        Map<String, String> params = new ParkApiUrl.Builder(getActivity()).buildParams();


        RequestBody height = RequestBody.create(MediaType.parse("text/plain"), params.get(ParkApiUrl.PARAM_HEIGHT));
        RequestBody width = RequestBody.create(MediaType.parse("text/plain"), params.get(ParkApiUrl.PARAM_WIDTH));
        RequestBody target = RequestBody.create(MediaType.parse("text/plain"), params.get(ParkApiUrl.PARAM_TARGET));

        requestDataMap.put(ParkApiUrl.PARAM_USER_NAME, userName);
        requestDataMap.put(ParkApiUrl.PARAM_USER_SECOND_NAME, userSecondName);
        requestDataMap.put(ParkApiUrl.PARAM_EMAIL, userEmail);
        requestDataMap.put(ParkApiUrl.PARAM_USER_ENCODED_PASSWORD, userPassword);
        requestDataMap.put(ParkApiUrl.PARAM_USER_GENDER, userGender);

        requestDataMap.put("form-data; name=\"photo\"; filename=\"image.jpg\"", avatar);

This is Retrofit suff:

    @Multipart
    @POST("/api/v2/user/email_register?_height=1184&_target=android/2&_width=768")
    Observable<UpdateUserInfoPayload> register(
            @Header("x-device-id") String deviceId,
            @PartMap() Map<String, RequestBody> map
    );
@kafji

This comment has been minimized.

Copy link

kafji commented Apr 21, 2016

@lectricas

This comment has been minimized.

Copy link

lectricas commented Apr 21, 2016

Yes, @kafji, I've seen this guide. It is for OKHTTP , not for retrofit. I've already implemented my request using okhttp only but it's not enough. I need to make it with retfit. Nice EXAMPLE android project with all the features implemented would be more that enought for all who struggles.

@markini

This comment has been minimized.

Copy link

markini commented Apr 21, 2016

My solution for this problem:

@Multipart
@POST("/api/.../{id}/audio")
Call<MyResponse> sendAudio(
        @Path("id") String id,
        @Part MultipartBody.Part part
);

Called like this:

RequestBody requestBody = RequestBody.create(MEDIA_TYPE_AUDIO, audioFile);
MultipartBody.Part part = MultipartBody.Part.createFormData("message_audio[audio]", audioFile.getName(), requestBody);
service.sendAudio(id, part)...
@sumit269

This comment has been minimized.

Copy link

sumit269 commented Apr 24, 2016

What worked for me is as follows:

@Multipart
    @POST("users/{id}/avatar")
    Observable<Void> uploadAvatar(@Header("Authorization") String token, @Path("id") String userId, @Part("source\"; filename=\"image.jpg") RequestBody image);

Note that the difference from a few other answers here is filename="image.jpg" without the escape char at the end.

@lectricas

This comment has been minimized.

Copy link

lectricas commented Apr 27, 2016

  MultipartBody.Builder builder = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart(ParkApiUrl.PARAM_USER_NAME, name)
                .addFormDataPart(ParkApiUrl.PARAM_USER_SECOND_NAME, last)
                .addFormDataPart(ParkApiUrl.PARAM_EMAIL, email)
                .addFormDataPart(ParkApiUrl.PARAM_USER_ENCODED_PASSWORD,
                        PasswordUtils.encodePassword(pwd))
                .addFormDataPart(ParkApiUrl.PARAM_USER_GENDER, sex)
                .addFormDataPart(ParkApiUrl.PARAM_PARSE_ID,
                        ParseInstallation.getCurrentInstallation().getObjectId());

        if (!TextUtils.isEmpty(avatarPath)) {

            Log.d("RegistrationFragment", avatarPath);
            File file = new File(avatarPath);
            int size = (int) file.length();
            byte[] bytes = new byte[size];
            try {
                BufferedInputStream buf = new BufferedInputStream(new FileInputStream(file));
                buf.read(bytes, 0, bytes.length);
                buf.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            builder.addPart(Headers.of("Content-Disposition", "form-data; name=\"photo\"; filename=\"image.jpg\""), RequestBody.create(MEDIA_TYPE_JPG, bytes));
        }

work like a charm!

@mikhail24

This comment has been minimized.

@sbljayarathna

This comment has been minimized.

Copy link

sbljayarathna commented Jul 8, 2016

This is my code. This works...


public interface FileUploadService {  
    @Multipart
    @POST("upload")
    Call<ResponseBody> upload(@PartMap Map<String, RequestBody> params);
}

 private void uploadFile() {  
        FileUploadService service =
                ServiceGenerator.createService(FileUploadService.class);

        File file = new File(selectedImagePath);
image_name = file.getName();
String fileName = "file\"; filename=\"" + image_name;
RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), file);

 RequestBody id = RequestBody.create(MediaType.parse("multipart/form-data"), observation_id);

Map<String, RequestBody> requestBodyMap = new HashMap<>();
 requestBodyMap.put("id", id);
requestBodyMap.put(fileName, requestBody);


        Call<ResponseBody> call = service.upload(requestBodyMap);
        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call,
                                   Response<ResponseBody> response) {
                Log.v("Upload", "success");
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                Log.e("Upload error:", t.getMessage());
            }
        });
    }
@Tar-SSA

This comment has been minimized.

Copy link

Tar-SSA commented Jul 8, 2016

This is my code and it's working flawlessly

Service

@Multipart
@POST("File/upload")
Observable<UploadImageApiResult> uploadImage(
    @Part("token") RequestBody token,
    @Part("player_id") RequestBody playerId,
    @Part MultipartBody.Part image
);

Call

restClient.getImageService().uploadImage(
    RequestBody.create(MediaType.parse("text/plain"), getApiToken()),
    RequestBody.create(MediaType.parse("text/plain"), form.getPlayerId()),
    MultipartBody.Part.createFormData(
        "file",
        form.getFile().getName(),
        RequestBody.create(MediaType.parse("image/*"), form.getFile())
    )
)
@bhargavms

This comment has been minimized.

Copy link

bhargavms commented Jul 12, 2016

@Tar-SSA How are you able to use @Part without passing a value to it like so @Part("blah") ?? that annotation gives a compile time error if one uses it like you have

@Tar-SSA

This comment has been minimized.

Copy link

Tar-SSA commented Jul 12, 2016

@bhargavms

This is my dependencies related to Retrofit

compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'
compile 'com.squareup.okhttp3:okhttp-urlconnection:3.2.0'
compile 'com.squareup.okhttp3:okhttp:3.2.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.2.0'

Are they the same with yours?

@bhargavms

This comment has been minimized.

Copy link

bhargavms commented Jul 12, 2016

@Tar-SSA ah thank you I was still using the 2.0.0-beta version and hence the issue

@pro100svitlo

This comment has been minimized.

Copy link

pro100svitlo commented Jul 18, 2016

I was never work with Jsoup before, and now I have a project, where guys were using JSoup lib, and I need to do some refactoring and make same work but with retrofit2...

I stuck with converting request that send image file. Here is original JSoup request:

Connection.Response result = Jsoup.connect(apiURL + "sendImg/")
                                    .method(Connection.Method.POST)
                                    .header("Token", XCSRFToken)
                                    .data("source", currentImage.getMD5().concat(".jpg"), 
                                           new FileInputStream(bitmapURI.getPath()))
                                    .execute();

here is what i try to do with retrofit:

```

@multipart
@post("sendImg/")
Call sendImage(@Header("Token") String token, @part MultipartBody.Part file);

public void sendImage(File file) {
        RequestBody requestFile =
                RequestBody.create(MediaType.parse("multipart/form-data"), file);
        MultipartBody.Part body =
        MultipartBody.Part.createFormData("source",
                        currentImage.getMD5().concat(".jpg"), requestFile);
        mSendImageCall = mServerApi.sendImage(getToken(), body);
        mSendImageCall.enqueue(sendImageCallback);
}
but request still failed...

Any ideas how convert that request correct? Thanks!
@pro100svitlo

This comment has been minimized.

Copy link

pro100svitlo commented Jul 21, 2016

@Tar-SSA , @sbljayarathna , @lectricas , @markini , @jemshit , @CateyesLin , @DeepakRattan ??
Anyone? Please help to find solution!

@JakeWharton

This comment has been minimized.

Copy link
Collaborator

JakeWharton commented Jul 21, 2016

This is not a help forum. Try StackOverflow.

@aman4india

This comment has been minimized.

Copy link

aman4india commented Sep 29, 2016

@multipart
@post("/uploadFile")
Call postFile(
@part("empsno") String empsno,
@part("storesno") String storesno,
@part("lrSno") String lrSno,
@part("recQty") String recQty,
@part("recVol") String recVol,
@part("recWgt") String recWgt,
@part("damageQty") String damageQty,
@part("looseQty") String looseQty,
@part("deliveryDate") String deliveryDate,
@part("deliveryTime") String deliveryTime,
// @part("uploadFile") RequestBody file,
// @part("uploadFile";filename="audex.jpg" ") RequestBody part,
@part("remarks") String remarks,
@part("receivedBy") String receivedBy,
@part("ipAddress") String ipAddress,
@part MultipartBody.Part images
);

          private void uploadFile(Uri fileUri) {
           File file = new File(fileUri.getPath());
          if (file.exists()) {
            Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(ScalarsConverterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        Log.e(TAG, "uploadFile:File " + file);
        MediaType MEDIA_TYPE_PNG = MediaType.parse("multipart/form-data");

        AudexInterface service = retrofit.create(AudexInterface.class);

        RequestBody requestFile = RequestBody.create(MEDIA_TYPE_PNG, file);

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

        Log.e(TAG, "uploadUri: " + strEmpsno + " " + strStoreSno + "  " + strLrno + "  " + strRecqty + "  " + strDeliverydate + " " + strDeliverytime);
        Call<PODResponse> call = service.postFile(strEmpsno,
                strStoreSno,
                strLrno,
                strRecqty,
                strRecvol,
                strRecwgt,
                strDamageqty,
                strLooseqty,
                strDeliverydate,
                strDeliverytime,
                //                    requestFile,
                strRemarks,
                strReceivedby,
                strIpaddress,
                filePart);

        call.enqueue(new Callback<PODResponse>() {
            @Override
            public void onResponse(Call<PODResponse> call, Response<PODResponse> response) {
                Log.e(TAG, "onResponse:uploadUri " + response.isSuccessful());
                if (response.isSuccessful()) {
                    Log.e(TAG, "uploadUri: " + response.body().getResult());
                }
            }

            @Override
            public void onFailure(Call<PODResponse> call, Throwable t) {
                Log.e(TAG, "onFailure:uploadUri " + t.getLocalizedMessage());
            }
        });

    }
}

I also tried this way but not getting success. Server is asking for "insert your image". please help me

@baguzajja

This comment has been minimized.

Copy link

baguzajja commented Nov 10, 2016

If i look your code
from

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

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

and

call for file with name
filePart

I hope work

@ghost

This comment has been minimized.

Copy link

ghost commented Nov 25, 2016

@ayon115 it solve my problem thank you very much, before i user @part("username") String username ,there are a exception JSON must start with an array or an object. but when i use your solution,just change String to RequestBoby,it help me .thank you

@ayon115

This comment has been minimized.

Copy link

ayon115 commented Jan 4, 2017

Glad to know it helped you :) @jounghu

@BabuinGH

This comment has been minimized.

Copy link

BabuinGH commented Jun 2, 2017

@ayon115 , I am having problem uploading a video to server using Retrofit2 multipart. Please could you help? I have posted a question in stackverflow. https://stackoverflow.com/questions/44319052/upload-video-using-retrofit2

@vivekkiran

This comment has been minimized.

Copy link

vivekkiran commented Jul 26, 2017

Thank you, everyone, for your solutions, it helped me a lot and resolved my issues, this issue thread is a great guide for other developers facing similar issues.

@hb-vijaypalod

This comment has been minimized.

Copy link

hb-vijaypalod commented Dec 18, 2017

I need to upload file inside a JSON object like below.

[
  {
    "imageType": "image_type",
    "image": "imageObj",  //Image File Here
    "imageName": "abc1"
  },
  {
    "imageType": "image_type",
    "image": "imageObj", //Image File Here
    "imageName": "abc2"
  }
]

How to achieve this via retrofit 2.0.

@asywalulfikri

This comment has been minimized.

Copy link

asywalulfikri commented Dec 20, 2017

How to upload image and content in the same time with retrofit use Oauth 1.0

@maheshsuthar93

This comment has been minimized.

Copy link

maheshsuthar93 commented Jan 22, 2018

Hello any one can help me to upload audio file using retrofit i am not able to upload audio file and play it

@maheshsuthar93

This comment has been minimized.

Copy link

maheshsuthar93 commented Feb 2, 2018

@fanshidong1993

This comment has been minimized.

Copy link

fanshidong1993 commented Jul 17, 2018

@markini thank u

@fanshidong1993

This comment has been minimized.

Copy link

fanshidong1993 commented Jul 17, 2018

来自中国的娃娃们,看这里。

@multipart
@post("/api/.../{id}/audio")
Call sendAudio(
@path("id") String id,
@part MultipartBody.Part part
);

RequestBody requestBody = RequestBody.create(MEDIA_TYPE_AUDIO, audioFile);
MultipartBody.Part part = MultipartBody.Part.createFormData("message_audio[audio]", audioFile.getName(), requestBody);
service.sendAudio(id, part)...

@markini 这位大佬的方案亲测有效。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment