7

I am looking for an example how could I send file and other params together to server.

I have to send server JSON which

{ "title": "title", "file": "uploaded file instance", "location": { "lat": 48.8583, "lng": 2.29232, "place": "Eiffel Tower" } } 

How could I create Retrofit to handle this case?

If file is a string I know how to handle this. If file is File object I have no idea how to do this.

2
  • this was already answer here stackoverflow.com/a/34562971/6689101 Commented Oct 12, 2016 at 21:48
  • but how to set lat,lng,place into location object? Commented Oct 12, 2016 at 21:51

2 Answers 2

8

Use gson and create a model class for the location.

Add the following dependencies to your build.gradle.

compile 'com.squareup.retrofit2:converter-gson:2.0.0' compile 'com.google.code.gson:gson:2.5' 

Create a model to represent the location.

public class Location { double lat; double lng; String location; public Location(double lat, double lon, String place) { this.lat = lat; this.lon = long; this.place = place; } } 

If the variable names for the payload fields don't match the actual required name for the endpoint you will need to add the annotation @SerializedName([expected name])

ex:

import com.google.gson.annotations.SerializedName; public class Location { @SerializedName("lat") double latitude; @SerializedName("lng") double longitude; @SerializedName("place") String location; public Location(double lat, double lon, String place) { latitude = lat; longitude = long; location = place; } } 

Define the api interface.

public interface Api { @POST("upload/") @Multipart Call<ResponseBody> uploadFile(@Part("title") RequestBody title, @Part MultipartBody.Part imageFile, @Part("location") Location location ); } 

Create a Retrofit instance and call the api.

File file; // create retrofit instance Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://baseurl.com/api/") .addConverterFactory(GsonConverterFactory.create()) .build(); // create api instance Api api = retrofit.create(Api.class); // create call object Call<ResponseBody> uploadFileCall = api.uploadFile( RequestBody.create(MediaType.parse("text/plain"), "title"), MultipartBody.Part.createFormData( "file", file.getName(), RequestBody.create(MediaType.parse("image"), file)), new Location(48.8583, 2.29232, "Eiffel Tower")); // sync call try { ResponseBody responseBody = uploadFileCall.execute().body(); } catch (IOException e) { e.printStackTrace(); } // async call uploadFileCall.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { if (response.isSuccessful()) { // TODO } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { // TODO } }); 

You will need to change the MediaType.parse() call if you are not using an image file.

You can similarly create a custom response type object and replace ResponseBody with it to receive a deserialized result object.

Let me know if this works. I didn't have a chance to test in your exact scenario obviously but I'm fairly confident this should work. The only part I'm not 100% on is whether @Part("location") Location location should be @Body("location") Location location

Sign up to request clarification or add additional context in comments.

1 Comment

And if in the json, the file was in location as the methods of the api interface would be? It's what I'm looking for
3

As of 02.2020 @Abtin Gramian's answer is great, except RequestBody.create() and MediaType.parse() are deprecated in Kotlin, so you have to use:

file.asRequestBody("image".toMediaTypeOrNull()) 

instead of:

RequestBody.create(MediaType.parse("image"), file) 

Also, I had to write the following manually:

import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.RequestBody.Companion.asRequestBody 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.