How do I rename a file to google drive rest api? Retrofit2 - android

In the Google documentation about it is not written, I use retrofit 2. Help. Write what request should be sent and what parameters to transmit
interface:
#PATCH("drive/v3/files/{fileId}")
#Multipart
Call<ResponseBody> renameFileGoogle(
#Path("fileId")String fileId,
#Part MultipartBody.Part metaPart
);
call metod:
public void renameMetod(String id, String title) {
String content = "{\"name\": \"" + title + "\"}";
MediaType contentType = MediaType.parse("application/json; charset=UTF-8");
MultipartBody.Part metaPart = MultipartBody.Part.create(RequestBody.create(contentType, content));
Call<ResponseBody> renameRequest = server.renameFileGoogle(id, metaPart);
renameRequest.enqueue(new Callback<ResponseBody>()...

It's there in the documentation https://developers.google.com/drive/v2/reference/files/patch
You need to send an HTTP PATCH request
PATCH https://www.googleapis.com/drive/v2/files/{fileId}
RequestBody:
{"title":"newTitle"}
For version 3
https://developers.google.com/drive/v3/reference/files/update
PATCH https://www.googleapis.com/drive/v3/files/{fileId}
RequestBody:
{"name":"newTitle"}

Related

Problem with working with Multipart form data Retrofit2

I know it is not wise to use multipart for simple text authentication. but I need to use it with api provided to me.
I tried all the methods possible.
It's working fine with postman
but not with retrofit 2
request type details
request type details
code used
tried
//RequestBody requestNameRq = RequestBody.create(MediaType.parse("text/plain"),serviceNameValue);
//RequestBody requestAmountRq = RequestBody.create(MediaType.parse("text/plain"),serviceAmountValue.toString());
/* Create Request Body */
//MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM)
// .addFormDataPart("service",serviceNameValue)
// .addFormDataPart("amount", String.valueOf(serviceAmountValue));
//RequestBody requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM)
// .addFormDataPart("service",serviceNameValue)
// .addFormDataPart("amount",serviceAmountValue.toString()).build();
//MultipartBody.Part multipartRequestBody = MultipartBody.Part
// .createFormData("service",serviceNameValue)
// .createFormData("amount",serviceAmountValue.toString());
//MultipartBody multipartBody = builder.build();
Code for Apiservice
#POST("services")
Call<AddServiceResponse> addService(#Header("Authorization") String authToken,
//#Body MultipartBody body);
#Part("service") RequestBody service,
#Part("amount") RequestBody amount);
//#Part("service") String service,
//#Part("amount") String password);
//#Part("service") RequestBody service,
//#Part("amount") RequestBody amount);
}
Please try to add
#Multipart
before
#POST("services")
Modify your ApiService class
#Multipart
#POST("services")
Call<AddServiceResponse> addService(
#Header("Authorization") String authToken,
#Part("service") MultipartBody.Part service,
#Part("amount") MultipartBody.Part amount);
Then create MultipartBody
MultipartBody.Part serviceBody = MultipartBody.Part.createFormData("service", "Somethin2");
MultipartBody.Part amountBody = MultipartBody.Part.createFormData("amount", "2344");
Then call
apiService.addService(serviceBody, amountBody);

#Part in multipart sends the string parameters in double quote

Following API I called for Editing User Profile . I have to send user profile picture so I used multipart in API .
#Multipart
#POST(ApiURLs.EDIT_USER_PROFILE)
Call<EditProfileModel> EditUserProfile (#Part("user_id) String userId ,
#Part("user_name") String userName ,
#Part("language_id") String languageId ,
#Part("state_id") String stateId ,
#Part MultipartBody.Part
profilePicture);
When Service called the requested parameters would be like
"user_id" : ""23""
"user_name" : ""Keval Shukla""
"language_id": ""27""
"state_id" : "53""
how do i remove that double quote using MultiPart ?
It must be like -
#Multipart
#POST(ApiURLs.EDIT_USER_PROFILE)
Call<EditProfileModel> EditUserProfile (
#Part("user_id") RequestBody userId ,
#Part("user_name") RequestBody userName ,
#Part("language_id") RequestBody languageId ,
#Part("state_id") RequestBody stateId ,
#Part RequestBody profilePicture);
And, to create requestBody,
File file = new File(imageURI.getPath());
RequestBody fbody = RequestBody.create(MediaType.parse("image/*"), file); // File requestBody
RequestBody userName = RequestBody.create(MediaType.parse("text/plain"), userNameSTRING); // String requestBody
You can send parameters other than file as RequestBody.
#Multipart
#POST(ApiURLs.EDIT_USER_PROFILE)
Call<EditProfileModel> EditUserProfile (#Part("user_id) RequestBody userId ,
#Part("user_name") RequestBody userName ,
#Part("language_id") RequestBody languageId ,
#Part("state_id") RequestBody stateId ,
#Part MultipartBody.Part profilePicture);
To Convert String to RequestBody:
RequestBody requestBody = RequestBody.create(MediaType.parse("text/plain"), userName); // Here userName is String
You are doing it wrong way, when you are using MultiPart as body type you have to specify body type of each request parameter.
For example, you are sending file(image,video etc.) and string parameters. So you need to specify all the parameters and convert it to specific body type.
You need to divide parameters into two parts,
1) MultipartBody - For media file
2) RequestBody - For other string or other data type parameters
e.g.
/*Create API Method*/
#Multipart
#POST("apiurl")
Call<Object> callMethodName(#Part("mobile_no") RequestBody mobile_no, /*String param */
#Part("password") RequestBody password, /*String param */
#Part MultipartBody.Part profile_img /*file param */);
I have define Parse type as multipart/form-data, you can define as according to your requirements,
public static final String MULTIPART_TYPE = "multipart/form-data";
Now create request parameters as below,
/* Adding String Params*/
RequestBody reqNumber = RequestBody.create(MediaType.parse(Constants.MULTIPART_TYPE), number.toString());
RequestBody reqPass = RequestBody.create(MediaType.parse(Constants.MULTIPART_TYPE), pass.toString());
/* Adding File*/
File file = new File(selectedImagePath);
RequestBody requestFile = RequestBody.create(MediaType.parse(Constants.MULTIPART_TYPE), file);
bodyFile = MultipartBody.Part.createFormData("profile_img", file.getName(), requestFile);
As last step, you need to pass request parameter to API call method as below, so it can identify parameters and send it to server.
/* Call API Method */
RestClient.getApiClient().callMethodName(reqNumber, reqPass, bodyFile);
Use RequestBody instead of String.
#Part("user_id") RequestBody user_id,
To call it
String userId= "123456";
RequestBody id =
RequestBody.create(
okhttp3.MultipartBody.FORM, userId);

is it possible to pass a single item as multipart using retrofit?

#Multipart
#POST("/api/add-deal/")
public void addDeal(#Body Deal deal, #Part("image")TypedFile image,Callback<Response> callback);
I want to send only the image as multipart and the rest as is.Is there any possible way ? Even I tried to add TypedFile inside my Deal model but unable to annotate with #part
Yes, it is possible with Partmap annotation using hash map. For example-
#Multipart
#POST("/api/add-deal/")
Call<Response> addDeal(#PartMap
HashMap<String, RequestBody> hashMap);
In hashMap you can add no of url parameters as key and set your values using RequestBody class type. see how to convert String and Image to RequestBody.
public static RequestBody ImageToRequestBody(File file) { //for image file to request body
return RequestBody.create(MediaType.parse("image/*"),file);
}
public static RequestBody StringToRequestBody(String string){ // for string to request body
return RequestBody.create(MediaType.parse("text/plain"),string);
}
add params to hashmap-
hashMap.put("photo",ImageToRequestBody(imageFile)); //your imageFile to Request body.
hashMap.put("user_id",StringToRequestBody("113"));
//calling addDeal method
apiInterface.addDeal(hashMap);
Hope this helpful.
It seems that you can send your #Body as TypedString.
For example, convert your "#Body Deal deal" into JSON String, and send it as TypedString.
Details: How to send multipart/form-data with Retrofit?
#Multipart
#POST("/api/v1/articles/")
Observable<Response> uploadFile(#Part("author") TypedString authorString,
#Part("photo") TypedFile photoFile);
This worked for me: POST Multipart Form Data using Retrofit 2.0 including image
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 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();
}
});

Android & Retrofit2 - posting image file in multipart request

I'm making an app in which I have to send image from gallery to server.
These should be headers (according to apiary).
Content-Type:image/jpeg
X-Filename:photo.jpg
But in logs in interceptor, there is only X-Filename, even though I tried multiple ways and I'm running out of ideas.
Server responds with 200 but the next call (commit image) returns 500 with error at the end of post.
These are the methods:
#Multipart
#POST("uploads")
Observable<String> uploadImage(
#Header("Content-Type") String contentType,
#Header("X-Filename") String fileName,
#Header("Authorization") String token,
#Part MultipartBody.Part file
);
#GET("uploads/{fileId}/commit")
Observable<String> commitFile(
#Header("Content-Type") String type,
#Header("Authorization") String token,
#Path("fileId") String fileId
);
OkHttp client:
private OkHttpClient createApiClient(Context context) {
int cacheSize = 10 * 1024 * 1024; // 10 MiB
Cache cache = new Cache(context.getCacheDir(), cacheSize);
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.addInterceptor(chain -> {
Request request = chain.request().newBuilder().build();
request.newBuilder().addHeader("Content-Type", "application/json");
Timber.d("Request: [%s] %s", request.method(), request.url());
Timber.d("Request: %s", request.headers().toString());
if (request.body() != null) {
Timber.d("Request: %s", request.body().toString());
}
return chain.proceed(request);
});
builder.cache(cache);
return builder.build();
}
Resulting logs:
D/NetModule: Request: [POST] https://winged-guild-133523.appspot.com/api/v1/uploads
D/NetModule: Request: X-Filename: asura.png
Authorization: HAYVi3clcqjug53IPS6AYMgzCPGnDE3Si
D/NetModule: Request: retrofit2.RequestBuilder$ContentTypeOverridingRequestBody#7c37f46
Same thing happens with Postman - Postman screenshot
Commit fails with this error: (sorry for ugly formatting)
{
"errorCode": "ImagesServiceFailureException",
"errorParam": "",
"errorMessage":"com.google.appengine.api.images.ImagesServiceFailureException: "
}
As I said I'm running out of ideas and would greatly appreciate any help with this upload problem.
(edit) PS: by omitting #Header("Content-Type") String contentType in app and using application/x-www-form-urlencoded in Postman, image upload and commit are both successful, but Image at returned url has no metadata and therefore can't be displayed.
Do not use #Multipart. Instead, use something like this:
#POST("upload/image")
Observable<ResponseBody> uploadImage(#Body RequestBody body);
File imageFile = new File(path);
RequestBody body = RequestBody.create(MediaType.parse("image/jpeg"),imageFile);
api.uploadImage(body);
This is my code using retrofit
#Multipart
#POST(ServiceConfig.API_CREATE_DEPENDENT_ACCOUNT)
#Headers({
"Accept: application/json",
"Accept-Encoding: gzip"
})
Call<DataResponse<CreateDependentAccountResponse>> createDependentAccount(#Query(JioConstants.ParamQuery.TOKEN) String token,
#Query(JioConstants.ParamQuery.USER_ID) long userID,
#Query(JioConstants.ParamQuery.FIRST_NAME) String firstName,
#Query(JioConstants.ParamQuery.LAST_NAME) String lastName,
#Query(JioConstants.ParamQuery.GENDER) String gender,
#Query(JioConstants.ParamQuery.DOB) String dob,
#Query(JioConstants.ParamQuery.RELATIONSHIP_ID) long relationshipID,
#Query(JioConstants.ParamQuery.DISPLAY_UNIT) String displayUnit,
#Part("avatar\"; filename=\"picture.jpg\" ") RequestBody file);
and
RequestBody file = null;
if (mFileTemp != null) {
file = RequestBody.create(MediaType.parse("image/*"), mFileTemp);
} else {
file = RequestBody.create(MediaType.parse("image/*"), "");
}
manageCall(ServiceManager.INSTANCE2().
createDependentAccount(token, userID, firstName, lastName, gender, dob, relationshipID, displayUnit, file))
.enqueue(new SimplifiedCallback<CreateDependentAccountResponse>() {
#Override
public void success(CreateDependentAccountResponse data, String message) {
hideLoading();
Good luck. This is my game

AWS S3 Rest API with Android Retrofit V2 library, uploaded image is damaged

I'm trying upload a Image from my Android APP to Amazon AWS S3 and I need use AWS Restful API.
I'm using Retrofit 2 to make to the request.
My application is connecting successfully with Amazon S3 and performing the request as expected, but when I try to view the Image from the Bucket, the picture does not open. I downloaded the Image to my pc and tried to open but keep getting the message that the image is corrupted.
Lets see my complete code bellow.
My Gradle dependencies
compile 'com.squareup.retrofit:retrofit:2.0.0-beta1'
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta1'
compile 'net.danlew:android.joda:2.8.2'
Here is created a File and starts the request
File file = new File(mCurrentPhotoPath);
RequestBody body = RequestBody.create(MediaType.parse("image/jpeg"), file);
uploadImage(body, "photo_name.jpeg");
Retrofit Interface
public interface AwsS3 {
#Multipart
#PUT("/{Key}")
Call<String> upload(#Path("Key") String Key,
#Header("Content-Length") long length,
#Header("Accept") String accept,
#Header("Host") String host,
#Header("Date") String date,
#Header("Content-type") String contentType,
#Header("Authorization") String authorization,
#Part("Body") RequestBody body);
}
Utils class to the mount the credentials
public class AWSOauth {
public static String getOAuthAWS(Context context, String fileName) throws Exception{
String secret = context.getResources().getString(R.string.s3_secret);
String access = context.getResources().getString(R.string.s3_access_key);
String bucket = context.getResources().getString(R.string.s3_bucket);
return gerateOAuthAWS(secret, access, bucket,fileName);
}
private static String gerateOAuthAWS(String secretKey, String accessKey, String bucket, String imageName) throws Exception {
String contentType = "image/jpeg";
DateTimeFormatter fmt = DateTimeFormat.forPattern("EEE', 'dd' 'MMM' 'yyyy' 'HH:mm:ss' 'Z").withLocale(Locale.US);
String ZONE = "GMT";
DateTime dt = new DateTime();
DateTime dtLondon = dt.withZone(DateTimeZone.forID(ZONE)).plusHours(1);
String formattedDate = dtLondon.toString(fmt);
String resource = "/" + bucket + "/" + imageName;
String stringToSign = "PUT" + "\n\n" + contentType + "\n" + formattedDate + "\n" + resource;
Mac hmac = Mac.getInstance("HmacSHA1");
hmac.init(new SecretKeySpec(secretKey.getBytes("UTF-8"), "HmacSHA1"));
String signature = ( Base64.encodeToString(hmac.doFinal(stringToSign.getBytes("UTF-8")), Base64.DEFAULT)).replaceAll("\n", "");
String oauthAWS = "AWS " + accessKey + ":" + signature;
return oauthAWS;
}
}
Lastly the method to make a request
public void uploadImage(RequestBody body, String fileName){
String bucket = getString(R.string.s3_bucket);
Retrofit restAdapter = new Retrofit.Builder()
.baseUrl("http://" + bucket + ".s3.amazonaws.com")
.addConverterFactory(GsonConverterFactory.create())
.build();
AwsS3 service = restAdapter.create(AwsS3.class);
DateTimeFormatter fmt = DateTimeFormat.forPattern("EEE', 'dd' 'MMM' 'yyyy' 'HH:mm:ss' 'Z").withLocale(Locale.US);
String ZONE = "GMT";
DateTime dt = new DateTime();
DateTime dtLondon = dt.withZone(DateTimeZone.forID(ZONE)).plusHours(1);
String formattedDate = dtLondon.toString(fmt);
try {
String oauth = AWSOauth.getOAuthAWS(getApplicationContext(), fileName);
Call<String> call = service.upload(fileName, body.contentLength(), "/**", bucket + ".s3.amazonaws.com", formattedDate, body.contentType().toString(), oauth, body);
call.enqueue(new Callback<String>() {
#Override
public void onResponse(Response<String> response) {
Log.d("tag", "response : " + response.body());
}
#Override
public void onFailure(Throwable t) {
Log.d("tag", "response : " + t.getMessage());
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
I appreciate any helps, thanks in advance!
I have used Retrofit 2 resolve
and I use Body instead of Part for your RequestBody in interface
#PUT("")
Call<String> nameAPI(#Url String url, #Body RequestBody body);
and java code
// Prepare image file
File file = new File(pathImg);
RequestBody requestBody = RequestBody.create(MediaType.parse("image/jpeg"), file);
Call<String> call = SingletonApiServiceS3.getInstance().getService().nameAPI(
path,
requestBody
);
call.enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, final Response<String> response) {
if (response.isSuccessful()) {
// Your handling
} else {
// Your handling
}
}
#Override
public void onFailure(Call<String> call, Throwable t) {
Toast.makeText(getContext(), "onFailure : "+t.getMessage().toString(),Toast.LENGTH_SHORT).show();
}
});
I have the same problem, and as I use Fiddler checked the HTTP request content, I found retrofit 2.0.0 beta1 has a different with 1.9.0.
In my problem, the different of HTTP request content prevent server get the correct data.
In order to make a same HTTP request content, i do next steps using retrofit 2.0.0 deta1.
In the retrofit service, add a form-data header for the http request;
#Headers("Content-Type: multipart/form-data;boundary=95416089-b2fd-4eab-9a14-166bb9c5788b")
int retrofit 2.0.0 deta1, the header using #Multipart will get a data like this:
Content-Type: multipart/mixed
as the deafult value is mixed, and has no boundary title.
Do not using #Multipart to upload file, just using #Body RequestBody
if you using #Multipart to request Server, you have to pass param(file) through
#Part(key), then a new problem you will get. May be retrofit 2.0.0beta1 has a BUG ..., #Multipart generate a bad http request compile with 1.9.0.
When you call the method, you need pass MultipartRequestBody to #Body RequestBody
Using MultipartBuilder to create a MultipartRequestBody, when you new MultipartBuilder, call this consturt:
new MultipartBuilder("95416089-b2fd-4eab-9a14-166bb9c5788b")
the param is you set int #headers(boundary=)
builder.addFormDataPart(String name, String filename, RequestBody value)
This method will help form a data like below int HTTP request content:
Content-Disposition: form-data; name="imgFile";
filename="IMG_20150911_113029.jpg" Content-Type: image/jpg
Content-Length: 1179469
RequestBody value is what you has generate in your code.
I just resolve this problem temporary.
Hope can help you!
RequestBody avatarBody = RequestBody.create(MediaType.parse("image"),file);
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", file.getName(), avatarBody);
#Multipart
#POST(url)
Call<ResponseBody> uploadImageAmazon(
#Part MultipartBody.Part filePart);
I had same experience, and solved it by https://github.com/square/retrofit/issues/2424 this solution
You are sending a multipart payload, but forcing the Content-type to be image/jpeg. Your jpg is corrupt because S3 probably saved the multipart headers into your jpg file since you told it the whole message was a JPG. Since you do not actually have multiple parts to send, you can drop the Multipart annotation and use Body instead of Part for your RequestBody
public interface AwsS3 {
#PUT("/{Key}")
Call<String> upload(#Path("Key") String Key,
#Header("Content-Length") long length,
#Header("Accept") String accept,
#Header("Host") String host,
#Header("Date") String date,
#Header("Content-type") String contentType,
#Header("Authorization") String authorization,
#Body RequestBody body);
}
You should also be able to remove explicitly setting the Content-type and Content-length headers.
I haven't used Retrofit 2, just Retrofit 1, so YMMV, but I believe that the typical way to do what you're trying to do is to use TypedFile where you are attempting to use RequestBody.
I'm guessing that Retrofit uses RequestBody internally.
You would create the TypedFile something like:
TypedFile typedFile = new TypedFile("multipart/form-data", new File("path/to/your/file"));
and your interface would be:
#Multipart
#PUT("/{Key}")
Call<String> upload(#Path("Key") String Key,
#Header("Content-Length") long length,
#Header("Accept") String accept,
#Header("Host") String host,
#Header("Date") String date,
#Header("Content-type") String contentType,
#Header("Authorization") String authorization,
#Part("Body") TypedFile body);
}
There's a decent example at
https://futurestud.io/blog/retrofit-how-to-upload-files/
You can use retrofit 2 to upload the image/file
#Multipart
#POST("/api/attachment")
Call<JsonPrimitive> addAttachment(#Part MultipartBody.Part imageFile);
Now to make the call:
RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), file);
MultipartBody.Part imageFileBody = MultipartBody.Part.createFormData("file", file.getName(), requestBody);
Note : Make sure you are using retrofit2 as for some reason I was unable to upload image using retrofit1 library.

Categories

Resources