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

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.

Show comment
Hide comment
@JakeWharton

JakeWharton Sep 7, 2015

Collaborator

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.

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.

Show comment
Hide comment
@JakeWharton

JakeWharton Sep 7, 2015

Collaborator

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.

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.

Show comment
Hide comment
@VadimWelldone

VadimWelldone 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.

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.

Show comment
Hide comment
@JakeWharton

JakeWharton Sep 7, 2015

Collaborator

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).

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.

Show comment
Hide comment
@JakeWharton

JakeWharton Sep 7, 2015

Collaborator

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

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.

Show comment
Hide comment
@VadimWelldone

VadimWelldone 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).

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.

Show comment
Hide comment
@ACzChef

ACzChef 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

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.

Show comment
Hide comment
@VadimWelldone

VadimWelldone 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).

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.

Show comment
Hide comment
@ayon115

ayon115 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.

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.

Show comment
Hide comment
@jimxj

jimxj 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

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.

Show comment
Hide comment
@wKovacs64

wKovacs64 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.

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.

Show comment
Hide comment
@tevjef

tevjef Sep 25, 2015

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

tevjef commented Sep 25, 2015

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

@JakeWharton

This comment has been minimized.

Show comment
Hide comment
@JakeWharton

JakeWharton Sep 25, 2015

Collaborator

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).

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.

Show comment
Hide comment
@VadimWelldone

VadimWelldone 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.

@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.

Show comment
Hide comment
@waleoyediran

waleoyediran 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')>)])

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.

Show comment
Hide comment
@wKovacs64

wKovacs64 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.

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.

Show comment
Hide comment
@ayon115

ayon115 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.

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.

Show comment
Hide comment
@sungjin0213

sungjin0213 Sep 30, 2015

@ayon115 Thank you so much. It really helped.

@ayon115 Thank you so much. It really helped.

@mengoni

This comment has been minimized.

Show comment
Hide comment
@mengoni

mengoni Oct 6, 2015

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

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.

Show comment
Hide comment
@ayon115

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

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.

Show comment
Hide comment
@mhousser

mhousser 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,

@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.

Show comment
Hide comment
@wKovacs64

wKovacs64 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 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.

Show comment
Hide comment
@mhousser

mhousser 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..?)

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.

Show comment
Hide comment
@abcdeiko

abcdeiko Oct 26, 2015

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

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

@simpleton

This comment has been minimized.

Show comment
Hide comment
@simpleton

simpleton Oct 26, 2015

@ayon115
Thanks for you reply. I think there is a redundant comma in @part.
It should looks like 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);
    }

@ayon115
Thanks for you reply. I think there is a redundant comma in @part.
It should looks like 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);
    }
@tevjef

This comment has been minimized.

Show comment
Hide comment
@tevjef

tevjef Oct 26, 2015

@abcdeiko extend RequestBody to receive an instance of a callback/listener/progress in the constructor. In the writeTo(BufferedSink sink) method call the listener as the bytes are read and written to the sink.

//The constructor
    public ProgressRequestBody(final File file, final ProgressListener listener) {
        this.file = file;
        this.listener = listener;
    } 

//The method to overide
    @Override
    public void writeTo(BufferedSink sink) throws IOException {
        long fileLength = file.length();
        byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
        FileInputStream in = new FileInputStream(file);
        long total = 0;
        try {
            int read;
            while ((read = in.read(buffer)) != -1) {
                this.listener.onProgress(total, fileLength);
                total += read;
                sink.write(buffer, 0, read);
            }
        } finally {
            in.close();
        }
    }

//A simple callback
   public interface ProgressListener {
        void onProgress(final long current, final long max);
   }

tevjef commented Oct 26, 2015

@abcdeiko extend RequestBody to receive an instance of a callback/listener/progress in the constructor. In the writeTo(BufferedSink sink) method call the listener as the bytes are read and written to the sink.

//The constructor
    public ProgressRequestBody(final File file, final ProgressListener listener) {
        this.file = file;
        this.listener = listener;
    } 

//The method to overide
    @Override
    public void writeTo(BufferedSink sink) throws IOException {
        long fileLength = file.length();
        byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
        FileInputStream in = new FileInputStream(file);
        long total = 0;
        try {
            int read;
            while ((read = in.read(buffer)) != -1) {
                this.listener.onProgress(total, fileLength);
                total += read;
                sink.write(buffer, 0, read);
            }
        } finally {
            in.close();
        }
    }

//A simple callback
   public interface ProgressListener {
        void onProgress(final long current, final long max);
   }
@abcdeiko

This comment has been minimized.

Show comment
Hide comment
@abcdeiko

abcdeiko Oct 27, 2015

@tevjef thank you for reply.
My mistake was that i used old version (beta 1 instead beta 2).

@tevjef thank you for reply.
My mistake was that i used old version (beta 1 instead beta 2).

@timaxapa

This comment has been minimized.

Show comment
Hide comment
@timaxapa

timaxapa Oct 30, 2015

Can anybody show me working solution?

Can anybody show me working solution?

@enginebai

This comment has been minimized.

Show comment
Hide comment
@enginebai

enginebai Oct 30, 2015

Check #1217, for me, I have to put the image binary into request body of POST request, the following code is my woking solution:

  • API Service
@POST("trip/{tripId}/media/photos")
Call<MediaPost> postEventPhoto(
        @Path("eventId") int tripId,
        @Header("Authorization") String accessToken,
        @Query("direction") String direction,
        @Body RequestBody photo);
  • Caller
InputStream in = new FileInputStream(new File(media.getPath()));
byte[] buf;
buf = new byte[in.available()];
while (in.read(buf) != -1);
RequestBody requestBody = RequestBody
        .create(MediaType.parse("application/octet-stream"), buf);
Call<MediaPost> mediaPostCall = tripApiService.postTripPhoto(
        tripId,
        ((GlobalInfo) getApplicationContext()).getApiAccessToken(),
        direction,
        requestBody);

Check #1217, for me, I have to put the image binary into request body of POST request, the following code is my woking solution:

  • API Service
@POST("trip/{tripId}/media/photos")
Call<MediaPost> postEventPhoto(
        @Path("eventId") int tripId,
        @Header("Authorization") String accessToken,
        @Query("direction") String direction,
        @Body RequestBody photo);
  • Caller
InputStream in = new FileInputStream(new File(media.getPath()));
byte[] buf;
buf = new byte[in.available()];
while (in.read(buf) != -1);
RequestBody requestBody = RequestBody
        .create(MediaType.parse("application/octet-stream"), buf);
Call<MediaPost> mediaPostCall = tripApiService.postTripPhoto(
        tripId,
        ((GlobalInfo) getApplicationContext()).getApiAccessToken(),
        direction,
        requestBody);
@timaxapa

This comment has been minimized.

Show comment
Hide comment
@timaxapa

timaxapa Oct 30, 2015

Thanks, but it does not work in my case

Thanks, but it does not work in my case

@ayon115

This comment has been minimized.

Show comment
Hide comment
@ayon115

ayon115 Oct 30, 2015

@timaxapa , please explain your problem in more details. Then we might be able to help. I am using the solution I described above in my 5 projects, all are working nicely. So, as a checklist I can suggest the following.

Try to post your request with file upload with Postman or any Rest client and Know the following from that if your request and upload is successful.

  1. Request Param Type , i,e is JSON encoded request body / Form-data / Multipart / x-url-encoded . I know it's weird because in general file upload is a multipart request but Backend developers often make API in weird way.
  2. Content-Type , i,e your file's content type may be image/* or application/octet-stream or anything else.
  3. Filename, as you see we have sent filename as hardcoded string, so make sure you are sending correct file name.

Hopefully you'll get your solution by checking these things. Good luck.

ayon115 commented Oct 30, 2015

@timaxapa , please explain your problem in more details. Then we might be able to help. I am using the solution I described above in my 5 projects, all are working nicely. So, as a checklist I can suggest the following.

Try to post your request with file upload with Postman or any Rest client and Know the following from that if your request and upload is successful.

  1. Request Param Type , i,e is JSON encoded request body / Form-data / Multipart / x-url-encoded . I know it's weird because in general file upload is a multipart request but Backend developers often make API in weird way.
  2. Content-Type , i,e your file's content type may be image/* or application/octet-stream or anything else.
  3. Filename, as you see we have sent filename as hardcoded string, so make sure you are sending correct file name.

Hopefully you'll get your solution by checking these things. Good luck.

@abcdeiko

This comment has been minimized.

Show comment
Hide comment
@abcdeiko

abcdeiko Oct 30, 2015

@timaxapa
First of all check what version you are using now (it is shoulde equal or above retrofit 2.0 beta 2, if you are using beta 1 it didn't work).

In your gradle file:

 compile 'com.squareup.retrofit:retrofit:2.0.0-beta2'

Create API service like this:

@Multipart
@POST("/upload")    
// upload is a post field
// without filename it didn't work! I use a constant name because server doesn't save file on original name       
Call<JsonObject> uploadImage(@Part("upload\"; filename=\"1\" ") RequestBody file);

And call it in your method like this:

 public void upload(String path) { // path to file like /mnt/sdcard/myfile.txt        
        File file = new File(path);

        // please check you mime type, i'm uploading only images
        RequestBody requestBody = RequestBody.create(MediaType.parse("image/*"), file);

        Call<JsonObject> call = service.uploadImage(requestBody);


        call.enqueue(new Callback<JsonObject>() {
            @Override
            public void onResponse(Response<JsonObject> response, Retrofit retrofit) {
                // on request finish
            }

            @Override
            public void onFailure(Throwable t) {
                // on request error
            }
        });
    }

@timaxapa
First of all check what version you are using now (it is shoulde equal or above retrofit 2.0 beta 2, if you are using beta 1 it didn't work).

In your gradle file:

 compile 'com.squareup.retrofit:retrofit:2.0.0-beta2'

Create API service like this:

@Multipart
@POST("/upload")    
// upload is a post field
// without filename it didn't work! I use a constant name because server doesn't save file on original name       
Call<JsonObject> uploadImage(@Part("upload\"; filename=\"1\" ") RequestBody file);

And call it in your method like this:

 public void upload(String path) { // path to file like /mnt/sdcard/myfile.txt        
        File file = new File(path);

        // please check you mime type, i'm uploading only images
        RequestBody requestBody = RequestBody.create(MediaType.parse("image/*"), file);

        Call<JsonObject> call = service.uploadImage(requestBody);


        call.enqueue(new Callback<JsonObject>() {
            @Override
            public void onResponse(Response<JsonObject> response, Retrofit retrofit) {
                // on request finish
            }

            @Override
            public void onFailure(Throwable t) {
                // on request error
            }
        });
    }
@timaxapa

This comment has been minimized.

Show comment
Hide comment
@timaxapa

timaxapa Nov 1, 2015

@abcdeiko Thank you very much for this detailed answer!

timaxapa commented Nov 1, 2015

@abcdeiko Thank you very much for this detailed answer!

@derohimat

This comment has been minimized.

Show comment
Hide comment
@derohimat

derohimat Feb 17, 2016

thanks guys,

i resolved my problem at Retrofit 2.0.0beta-2 with this

@Multipart
@POST(URLCons.URL_UPLOAD_PHOTO_PROFILE)
Call<ApiResponse> uploadPhotoProfile(
        @Part("photo\"; filename=\"picture.jpg\" ") RequestBody requestBody,
        //alway send
        @Part("id_user") RequestBody id_user,
        @Part("sess_mobile") RequestBody sess_mobile);

thanks guys,

i resolved my problem at Retrofit 2.0.0beta-2 with this

@Multipart
@POST(URLCons.URL_UPLOAD_PHOTO_PROFILE)
Call<ApiResponse> uploadPhotoProfile(
        @Part("photo\"; filename=\"picture.jpg\" ") RequestBody requestBody,
        //alway send
        @Part("id_user") RequestBody id_user,
        @Part("sess_mobile") RequestBody sess_mobile);
@abhishekgargg

This comment has been minimized.

Show comment
Hide comment
@abhishekgargg

abhishekgargg Feb 18, 2016

i have tried all the solutions mentioned in this forum and am still not able to post a multipart file.
I am using beta3 version of retrofit.
At the backend, i am able to receive the request, but the multipart parameter is empty.
Can someone please suggest either another approach or a work-around?

i have tried all the solutions mentioned in this forum and am still not able to post a multipart file.
I am using beta3 version of retrofit.
At the backend, i am able to receive the request, but the multipart parameter is empty.
Can someone please suggest either another approach or a work-around?

@abcdeiko

This comment has been minimized.

Show comment
Hide comment
@abcdeiko

abcdeiko Feb 18, 2016

@abhishekgargg i think the best way to ask a question is using stackoverflow project.
Anyway, if you want to see any answers you should post some of your code.

@abhishekgargg i think the best way to ask a question is using stackoverflow project.
Anyway, if you want to see any answers you should post some of your code.

@CateyesLin

This comment has been minimized.

Show comment
Hide comment
@CateyesLin

CateyesLin Feb 25, 2016

If all the answer above are not worked. Try using @Body and compose RequestBody yourself.
Here is my approach:

@POST("me")
Call<RestaurantPhoto> update(@Body RequestBody body);
public Me update(String name, File photo) throws IOException, ApiException {
    RequestBody body = new MultipartBody.Builder()
            .setType(MultipartBody.FORM)
            .addFormDataPart("name", name)
            .addFormDataPart("photo", photo.getName(), 
                RequestBody.create(MediaType.parse("image/jpeg"), photo))
            .build();

    Response<Me> response = usersApi.update(body).execute();
    if(response.isSuccess()) {
        return response.body();
    } else {
        throw new ApiException(response);
    }
}

If all the answer above are not worked. Try using @Body and compose RequestBody yourself.
Here is my approach:

@POST("me")
Call<RestaurantPhoto> update(@Body RequestBody body);
public Me update(String name, File photo) throws IOException, ApiException {
    RequestBody body = new MultipartBody.Builder()
            .setType(MultipartBody.FORM)
            .addFormDataPart("name", name)
            .addFormDataPart("photo", photo.getName(), 
                RequestBody.create(MediaType.parse("image/jpeg"), photo))
            .build();

    Response<Me> response = usersApi.update(body).execute();
    if(response.isSuccess()) {
        return response.body();
    } else {
        throw new ApiException(response);
    }
}
@LuigiPapino

This comment has been minimized.

Show comment
Hide comment
@LuigiPapino

LuigiPapino Mar 2, 2016

#1063 (comment) worked for me.
All others approach don't :(

#1063 (comment) worked for me.
All others approach don't :(

@morder

This comment has been minimized.

Show comment
Hide comment
@ThiTrou

This comment has been minimized.

Show comment
Hide comment
@ThiTrou

ThiTrou Mar 19, 2016

Hello,

If instead of uploading an image on a server, I would have to upload an audio file ".mp4".
What would be the differences ?

When I will use Mediatype.parse what should be th string parameter of it ?

Thanks

ThiTrou commented Mar 19, 2016

Hello,

If instead of uploading an image on a server, I would have to upload an audio file ".mp4".
What would be the differences ?

When I will use Mediatype.parse what should be th string parameter of it ?

Thanks

@jemshit

This comment has been minimized.

Show comment
Hide comment
@jemshit

jemshit Mar 22, 2016

Back to old conversation, i have a web service which works with this request, which has only @Body contains text and images:

@POST(Constants.INSERT_POST)
    public void InsertPost(@Body MultipartTypedOutput attachments, CoreCallBack<PrimitiveResponse> OnResponse

And request is made here:

MultipartTypedOutput multipartTypedOutput = new MultipartTypedOutput();
multipartTypedOutput.addPart("Body", new TypedString(postBody));
multipartTypedOutput.addPart("Token", new TypedString(getToken()));
multipartTypedOutput.addPart("CategoryId", new TypedString(categoryId));
if (postPictures != null) {
      for (File file : postPictures) {
           multipartTypedOutput.addPart("photo" + postPictures.indexOf(file), new TypedFile("image/jpg", file));
       }
}
restClientApplication.getApiResponse().InsertPost(multipartTypedOutput, callBack);

After i move to Retrofit 2, this didn't work, i think it is because of MultipartTypedOutput. Then i changed above to this:

    @Multipart
    @POST("api/Post/Insert")
    Call<PrimitiveResponse> InsertPost(@PartMap() Map<String,RequestBody> mapFileAndName,
                                       @Part("Token") String Token,
                                       @Part("CategoryId") String CategoryId,
                                       @Part("Body") String Body);

which didn't work. Then i changed all Strings to RequestBody, now it works. Request is like below:

        HashMap<String, RequestBody> map=new HashMap<>(fileList.size());
        RequestBody file=null;
        for(int i=0,size=fileList.size(); i<size;i++) {
            file = RequestBody.create(MediaType.parse("image/jpg"), fileList.get(i));
            map.put("file\"; filename=\"" + "photoname" + i + ".jpg", file);
        }

        postService.InsertPost(map,
                RequestBody.create(MediaType.parse("text/plain"), realmManager.getToken()),
                RequestBody.create(MediaType.parse("text/plain"), categoryId),
                RequestBody.create(MediaType.parse("text/plain"), body));

I also had to change name along with filename, so this line is changed:
map.put("name"+i+"\"; filename=\"" + "photoname" + i +".jpg", file); // name, filename, file

If you have trouble with MultipartTypedOutput, name, filename on Retrofit2, you might want to check this.

jemshit commented Mar 22, 2016

Back to old conversation, i have a web service which works with this request, which has only @Body contains text and images:

@POST(Constants.INSERT_POST)
    public void InsertPost(@Body MultipartTypedOutput attachments, CoreCallBack<PrimitiveResponse> OnResponse

And request is made here:

MultipartTypedOutput multipartTypedOutput = new MultipartTypedOutput();
multipartTypedOutput.addPart("Body", new TypedString(postBody));
multipartTypedOutput.addPart("Token", new TypedString(getToken()));
multipartTypedOutput.addPart("CategoryId", new TypedString(categoryId));
if (postPictures != null) {
      for (File file : postPictures) {
           multipartTypedOutput.addPart("photo" + postPictures.indexOf(file), new TypedFile("image/jpg", file));
       }
}
restClientApplication.getApiResponse().InsertPost(multipartTypedOutput, callBack);

After i move to Retrofit 2, this didn't work, i think it is because of MultipartTypedOutput. Then i changed above to this:

    @Multipart
    @POST("api/Post/Insert")
    Call<PrimitiveResponse> InsertPost(@PartMap() Map<String,RequestBody> mapFileAndName,
                                       @Part("Token") String Token,
                                       @Part("CategoryId") String CategoryId,
                                       @Part("Body") String Body);

which didn't work. Then i changed all Strings to RequestBody, now it works. Request is like below:

        HashMap<String, RequestBody> map=new HashMap<>(fileList.size());
        RequestBody file=null;
        for(int i=0,size=fileList.size(); i<size;i++) {
            file = RequestBody.create(MediaType.parse("image/jpg"), fileList.get(i));
            map.put("file\"; filename=\"" + "photoname" + i + ".jpg", file);
        }

        postService.InsertPost(map,
                RequestBody.create(MediaType.parse("text/plain"), realmManager.getToken()),
                RequestBody.create(MediaType.parse("text/plain"), categoryId),
                RequestBody.create(MediaType.parse("text/plain"), body));

I also had to change name along with filename, so this line is changed:
map.put("name"+i+"\"; filename=\"" + "photoname" + i +".jpg", file); // name, filename, file

If you have trouble with MultipartTypedOutput, name, filename on Retrofit2, you might want to check this.

@yayaa

This comment has been minimized.

Show comment
Hide comment
@yayaa

yayaa Mar 31, 2016

I had the same issue on Retrofit version 2.0.0-beta3 and
Only @ayon115 RequestMap solution works, i couldn't get it work none of those others...

yayaa commented Mar 31, 2016

I had the same issue on Retrofit version 2.0.0-beta3 and
Only @ayon115 RequestMap solution works, i couldn't get it work none of those others...

@amitsharma1981

This comment has been minimized.

Show comment
Hide comment
@amitsharma1981

amitsharma1981 Apr 6, 2016

@JakeWharton @ayon115

Can someone help me with an example of using PartMap. Our rest method consumes one json object and an array of files using a multipart upload. Here is the method signature:

@RequestMapping(method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@ResponseStatus(HttpStatus.ACCEPTED)
public ResponseEntity submitJob(
@RequestPart("request")
final JobRequest jobRequest,
@RequestPart("attachment")
final MultipartFile[] attachments,
@RequestHeader(value = FORWARDED_FOR_HEADER, required = false)
final String clientHost,
final HttpServletRequest httpServletRequest
)

I have been trying so many different variations and struggling with it.

Thanks.

@JakeWharton @ayon115

Can someone help me with an example of using PartMap. Our rest method consumes one json object and an array of files using a multipart upload. Here is the method signature:

@RequestMapping(method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@ResponseStatus(HttpStatus.ACCEPTED)
public ResponseEntity submitJob(
@RequestPart("request")
final JobRequest jobRequest,
@RequestPart("attachment")
final MultipartFile[] attachments,
@RequestHeader(value = FORWARDED_FOR_HEADER, required = false)
final String clientHost,
final HttpServletRequest httpServletRequest
)

I have been trying so many different variations and struggling with it.

Thanks.

@scognito

This comment has been minimized.

Show comment
Hide comment
@scognito

scognito Apr 14, 2016

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

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

@lectricas

This comment has been minimized.

Show comment
Hide comment
@lectricas

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

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.

Show comment
Hide comment
@lectricas

This comment has been minimized.

Show comment
Hide comment
@lectricas

lectricas 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.

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.

Show comment
Hide comment
@markini

markini 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)...

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.

Show comment
Hide comment
@sumit269

sumit269 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.

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.

Show comment
Hide comment
@lectricas

lectricas 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!

  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!

@sbljayarathna

This comment has been minimized.

Show comment
Hide comment
@sbljayarathna

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

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.

Show comment
Hide comment
@Tar-SSA

Tar-SSA 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())
    )
)

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.

Show comment
Hide comment
@bhargavms

bhargavms 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 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.

Show comment
Hide comment
@Tar-SSA

Tar-SSA 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?

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.

Show comment
Hide comment
@bhargavms

bhargavms Jul 12, 2016

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

@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.

Show comment
Hide comment
@pro100svitlo

pro100svitlo 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 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.

Show comment
Hide comment

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

@JakeWharton

This comment has been minimized.

Show comment
Hide comment
@JakeWharton

JakeWharton Jul 21, 2016

Collaborator

This is not a help forum. Try StackOverflow.

Collaborator

JakeWharton commented Jul 21, 2016

This is not a help forum. Try StackOverflow.

@aman4india

This comment has been minimized.

Show comment
Hide comment
@aman4india

aman4india 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

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.

Show comment
Hide comment
@baguzajja

baguzajja 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

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.

Show comment
Hide comment
@ghost

ghost 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

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.

Show comment
Hide comment
@ayon115

ayon115 Jan 4, 2017

Glad to know it helped you :) @jounghu

ayon115 commented Jan 4, 2017

Glad to know it helped you :) @jounghu

@BabuinGH

This comment has been minimized.

Show comment
Hide comment
@BabuinGH

BabuinGH 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

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.

Show comment
Hide comment
@vivekkiran

vivekkiran 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.

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.

Show comment
Hide comment
@hb-vijaypalod

hb-vijaypalod 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.

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.

Show comment
Hide comment
@asywalulfikri

asywalulfikri Dec 20, 2017

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

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

@maheshsuthar93

This comment has been minimized.

Show comment
Hide comment
@maheshsuthar93

maheshsuthar93 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

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.

Show comment
Hide comment
@maheshsuthar93

maheshsuthar93 Feb 2, 2018

@fanshidong1993

This comment has been minimized.

Show comment
Hide comment
@fanshidong1993

This comment has been minimized.

Show comment
Hide comment
@fanshidong1993

fanshidong1993 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 这位大佬的方案亲测有效。

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