Send optional field and multipart in retrofit - android

I want to send image , name and city for the server and all of these can be optional but i don't know how the interface will look like i found a solution with overloading the methods but it makes the code complicated
The http method is PUT also .

Use the annotation for Multipart. Create a Map of city and name to be used as PartMap. Pass the image as MultipartBody. Something like this:
#Multipart
#POST("")
Call<ReturnType> yourCall(#Url String url, #PartMap() Map<String, RequestBody> params, #Part MultipartBody.Part multipart, ...);

Related

How to upload photo in android retrofit 2?

I can't upload photo to server. java.lang.IllegalArgumentException: #Field parameters can only be used with form encoding. (parameter #1). Please help me, how to solve or any other suggestions. postman
#FormUrlEncoded
#Multipart
#POST("qq/api/xxxx")
Call<Custom> postCustom(#Field("Id") String Id,
#Part MultipartBody.Part file,
#Field("Status") String Status);
Change your request interface like this
#Multipart
#POST("qq/api/xxxx")
Call<Custom> postCustom(
#Part("Id") String Id,
#Part MultipartBody.Part file,
#Part("Status") String Status);
You cannot use both #FormUrlEncoded and #Multipart on a single method since an HTTP request can only have one Content-Type. #FormUrlEncoded and #Multipart are both content types.
From Jake Wharton
You can have to use FormUrlEncodedTypedOutput as a #Part argument for the form encoded part and build it up yourself. The annotation on the method is for the outermost encoding which in this case is multipart.
References
I have added also these issue reference which is really helpful for you to understanding what you are about to change in your http request method
https://github.com/square/retrofit/issues/662
https://github.com/square/retrofit/issues/1210

How to pass extra post data when using Multipart in Retrofit?

I'm Using the below code in Android, retrofit, to upload an image:
#Multipart
#POST("uploadimage")
Call<ImageUploadResponse> uploadImage(#PartMap Map<String, RequestBody> map);
But what if I need to send extra data, such as Image Description along with the request?
I Was not able to use #Field, that is i tried like this:
#Multipart
#FormUrlEncoded
#POST("uploadimage")
Call<ImageUploadResponse> uploadImage(#PartMapMap<String,RequestBody> map,
#Field("description")String desc);
I got an error stating that only one annotation is allowed. That is either #Multipart or #FormUrlEncoded.
You can use #Part instead of #Field
#Multipart
#POST("uploadimage")
Call<ImageUploadResponse> uploadImage(#PartMap Map<String, RequestBody> map, #Part("description") String description);

Is it possible in Retrofit to use Form Encoded and Multipart in single request

Here is my sample code.
#Multipart
#POST("/upload-end-users-document")
Call<ListPinDevicesResponse<UploadEndUsersDocumentResponse>> getUploadEndUsersDocument(#PartMap Map<String, String> userParams,#PartMap Map<String, RequestBody> params,#Header("access-token") String accessToken);
is there a no way to use #Field and #part together in Retrofit??
If yes than tell a reason, If no tell me a proper way
I will appreciate your answer and thank you in advance.
Screenshots of Postman tool is attached in the link below.
https://drive.google.com/file/d/1J-MkO49gfXpYKwxyBqtzHqotnCgHJ9yp/view?usp=sharing
https://drive.google.com/file/d/1d1WZPHVSxFsvyY4zvXVmd9OBYcsSn3yG/view?usp=sharing

Retrofit: what is different between #Field and #Body

In some post request, I don't know when to use #Field, when to use #Body.
Like whats the difference between:
#POST("users/register")
Call<String> register(#Body RequestBody registerRequest);
and:
#POST("users/register")
Call<String> register(#Field String id, #Field String pass);
Can I use #Body instead of #Field, and reverse ? If not, why ? And how to know this case use #Body, other case use #Field ?
Can you please give me some case and explain, thank you.
#Body – Sends Java objects as request body.
#Field – send data as form-urlencoded. This requires a #FormUrlEncoded annotation attached with the method.
The #Field parameter works only with a POST. #Field requires a mandatory parameter. In cases when #Field is optional, we can use #Query instead and pass a null value.
Both are used for posting data only, but they have following difference -
The #Body annotation defines a single request body.
interface Foo {
#POST("/jayson")
FooResponse postJson(#Body FooRequest body);
}
That means if you are using #Body, it should be only parameter. It is helpful when you have already a JsonObject and you want to send it as it with you api call.
Another way is, you can send data using #Field and send the Place object as a JSON string.
#POST("/post/addphoto/")
public void addImage(#Field("image_url") String url, #Field("caption") String caption, #Field("google_place_id") String placeId, #Field("facebook_place") String place, Callback<UploadCallBack> response);
Hope it will help... :-)

Multipart Upload to Amazon S3 using Retrofit

I'm attempting to convert all my asynctasks and HttpPost code to use Retrofit, so far so good, but I'm having trouble uploading user files to an amazon s3 bucket.
The file upload has two parts:
Query api to get a upload_url and amazon upload params.
Upload File to specified location with params provided in first call.
Here's an example list of parameters provided to me from the first call. According to the documentation, these values can change or not be included, and the 2nd api call must call use these params in the exact order they were provided.
"AWSAccessKeyId": "some_id",
"key": "/users/1234/files/profile_pic.jpg",
"acl": "private",
"Filename": "profile_pic.jpg",
"Policy": "some_opaque_string",
"Signature": "another_opaque_string",
"Content-Type": "image/jpeg"
In order to deal with the dynamic content. I created a custom converter to have retrofit return me a LinkedHashMap in my first API call.
public class CustomConverter implements Converter {
#Override public Object fromBody(TypedInput typedInput, Type type) throws ConversionException {
...
Type mapType = new TypeToken<LinkedHashMap<String, String>>(){}.getType();
return new Gson().fromJson(JSON_STRING, mapType);
}
Then in the second api call, Once I have these values I create a FormUrlEncodedTypedOutput by iterating over the HashMap and adding each item.
FormUrlEncodedTypedOutput params = new FormUrlEncodedTypedOutput();
for (Map.Entry<String, String> entry : uploadParams.entrySet()) {
params.addField(KEY, VALUE);
}
Everything up to here seems to be working. I'm getting the necessary upload params and the ordering seems to be consistent. I'm a bit less sure about how I have my multipart retrofit call setup. I then use that inside a synchronous retrofit call inside an intentservice.
#Multipart
#POST("/")
Response uploadFile(#Part ("whatdoesthisdo?") FormUrlEncodedTypedOutput params, #Part("File") TypedFile file);
This results in a Amazon error.
"code" : "InvalidArgument"
"message" : "Bucket POST must contain a field named 'key'. If it is specified, please check the order of the fields."
I've been googling and it seems like Amazon prefers the "key" value to be first? However, if i put the "key" in front of "AWSAccessKeyId" I get a 403 unauthorized error. Do i have my retrofit call setup correctly? If someone could help me figure this out, I'd appreciate it. It's taken a few days to convert most of my uploading code over to retrofit and if I've been stuck on this for a while.
Thanks!
Solution was to use a #PartMap instead of the FormUrlEncodedTypedOutput.
#Multipart
#POST("/")
Response uploadFile(#PartMap LinkedHashMap<String,String> params, #Part("File") TypedFile file);

Categories

Resources