I am using retrofit2+rxAndroid to work with REST. I want to send multipart request with image and text. But something is not working and instead of image+ text I have this "trim,nshtml,max|140".
This is my request:
#Multipart
#POST("feed/post/add")
public Observable<VehicleSearchResponse>
addPost(#Header("Authorization") String token, #Header("Content-Type") String contenttype,
#Part("text") String message,
#Part("attached_images") RequestBody file);
And this is how I form my RequestBody
RequestBody.create(MediaType.parse("image/jpg"), persistImage(bitmap2, "test"))
Please help me.
Have you tried using:
MultipartBody.create(MultipartBody.FORM, bytes)
for the attached_images part?
Related
I am trying to post some multipart form data via Retrofit in Android to a web service.
The web services's API expects the following parameters to be passed as field of a multipart form data:
Name Type
company_id text/plain
image image/*
It also expects an authorization token to be passed as a query string parameter.
So i have defined my API interface call like this:
#Multipart
#POST("/companies/uploadImage")
#Headers({
"Content-Type: multipart/form-data",
"Accept: application/json"
})
Call<ServerResponse> companyUploadImage( #Part("company_id") RequestBody companyId, #Part MultipartBody.Part file, #Query("token") String token);
Afterwards this is how i call the above API interface method in a custom class:
RequestBody companyId = RequestBody.create(MediaType.parse("text/plain"), LocalStorage.getInstance().getCompanyId());
File file = new File(postPath);
MultipartBody.Part image = MultipartBody.Part.createFormData("image", file.getName(), RequestBody.create(MediaType.parse("image/*"), file));
Call<ServerResponse> uploadProfileImage = router.companyUploadImage(companyId, image, token);
uploadProfileImage.enqueue(new Callback<ServerResponse>() {
#Override
public void onResponse(Call<ServerResponse> call, Response<ServerResponse> response) {
Log.e("Upload Profile Image: ", response.body().getMessage());
}
#Override
public void onFailure(Call<ServerResponse> call, Throwable t) {
Log.e("Upload Profile Image Error: ", t.getMessage());
}
});
The request is sent successfully to the server, so no networking exceptions occur, however the multipart form values, company_id and image, are received empty on the server side
Any idea?
Thank you!
I managed to solve the issue. It seems that the solution was as simple as removing the #Header annotation from the API interface method. So now it looks like this:
#Multipart
#POST("/companies/uploadImage")
Call<ServerResponse> companyUploadImage( #Part("company_id") RequestBody companyId, #Part MultipartBody.Part file, #Query("token") String token);
Maybe someone will find this post helpful.
I'm trying to upload a file to Amazon's S3 using a pre-signed URL. I get the URL from a server which generates the URL & sends it to me as part of a JSON object. I get the URL as a String, something like this:
https://com-example-mysite.s3-us-east-1.amazonaws.com/userFolder/ImageName?X-Amz-Security-Token=xxfooxx%2F%2F%2F%2F%2F%2F%2F%2F%2F%2Fxxbarxx%3D&X-Amz-Algorithm=xxAlgoxx&X-Amz-Date=20170831T090152Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=xxcredxx&X-Amz-Signature=xxsignxx
Unfortunately, when I pass this to Retrofit2, it modifies the String attempting to make it into a URL. I've set encoding=true which took care of most of the problem but not completely. I know the String works as it is. I've tried it in Postman & get a successful response.
1st I tried just putting the String (except for what I cut out as baseUrl) as a whole into the Path
public interface UpdateImageInterface {
#PUT("{url}")
Call<Void> updateImage(#Path(value="url", encoded=true) String url, Body RequestBody image);
}
The calling code:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://com-example-mysite.s3-us-east-1.amazonaws.com/userFolder/")
.build();
UpdateImageInterface imageInterface = retrofit.create(UpdateImageInterface.class);
// imageUrl is "ImageName..."
Call<Void> call = imageInterface.updateImage(imageUrl, requestFile);
This works mostly except the the '?' (after "ImageName") get converted to "%3F". This causes a Bad Request / 400.
My next attempt was to create a query with Retrofit2 but then dump the whole String (with multiple queries) into the query.
public interface UpdateImageInterface {
#PUT("ImageName")
Call<Void> updateProfilePhoto(#Query(value="X-Amz-Security-Token", encoded = true) String token, #Body RequestBody image);
}
The calling code:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://com-example-mysite.s3-us-east-1.amazonaws.com/userFolder/")
.build();
UpdateImageInterface imageInterface = retrofit.create(UpdateImageInterface.class);
// imageUrl is "xxfooxx..."
Call<Void> call = imageInterface.updateImage(imageUrl, requestFile);
This gets the '?' rendered correctly but all of the '&' get changed to "%26"
Lastly I tried passing the whole String in baseUrl() but that gives an IllegalArgumentException for not having '/' on the end.
I know that I could parse the pre-signed URL to make multiple queries & assemble them in Retrofit2 as queries should be done but I'd like to avoid that processing.
To restate the question:
Is there a way to easily (without heavy String parsing) upload a file to S3 with a pre-signed URL using Retrofit2?
With help from a colleague, this is the solution.
public interface UpdateImageInterface {
#PUT
Call<Void> updateImage(#Url String url, #Body RequestBody image);
}
Calling code:
String CONTENT_IMAGE = "image/jpeg";
File file = new File(localPhotoPath); // create new file on device
RequestBody requestFile = RequestBody.create(MediaType.parse(CONTENT_IMAGE), file);
/* since the pre-signed URL from S3 contains a host, this dummy URL will
* be replaced completely by the pre-signed URL. (I'm using baseURl(String) here
* but see baseUrl(okhttp3.HttpUrl) in Javadoc for how base URLs are handled
*/
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://www.dummy.com/")
.build();
UpdateImageInterface imageInterface = retrofit.create(UpdateImageInterface.class);
// imageUrl is the String as received from AWS S3
Call<Void> call = imageInterface.updateImage(imageUrl, requestFile);
Javadoc for info on #Url (class Url) &
baseUrl() (class Retrofit.Builder)
MediaType is a class in the OkHttp library that is often used with Retrofit (both from Square). Info about constants passed to the parse method can be found in the Javadoc.
Use the following while uploading directly to S3 using presigned URL.
#Multipart
#PUT
#Headers("x-amz-acl:public-read")
Call<Void> uploadFile(#Url String url, #Header("Content-Type") String contentType, #Part MultipartBody.Part part);
I tried work with API
My API
And Java code
public interface UploadAPI {
#Multipart
#POST("books")
Call<AddBookResult> uploadBook(
#Part MultipartBody.Part audios,
#Part("image") RequestBody image,
#Part("audio_names") List<String> audio_names,
#Part("video_names") List<String> video_names,
#Part("video_urls") List<String> video_urls,
#Part("preview") RequestBody preview,
#Part("hot") String hotParam,
#Part("new") String newParam,
#Part("coming") String comingParam,
#Part("sale_offs") List<String> sale_offs,
#Part("author") String author,
#Part("publisher") String publisher,
#Part("categories") List<String> categories,
#Part("name") String name,
#Part("price") String price
);
}
Call API
Code Java Call API
And result of respone
Internal Server Error
:(
First of all internal server error (status code 500) means that you have some kind of issue with your backend or your API cannot find the path to the called endpoint controller.
Im not sure how is your backend configured, but i think it may be the path problem, try adding the "/" before books in request declaration like this
public interface UploadAPI {
#Multipart
#POST("/books") //here you have to put path to your controller
Call<AddBookResult> uploadBook(
#Part MultipartBody.Part audios,
#Part("image") RequestBody image,
#Part("audio_names") List<String> audio_names,
#Part("video_names") List<String> video_names,
#Part("video_urls") List<String> video_urls,
#Part("preview") RequestBody preview,
#Part("hot") String hotParam,
#Part("new") String newParam,
#Part("coming") String comingParam,
#Part("sale_offs") List<String> sale_offs,
#Part("author") String author,
#Part("publisher") String publisher,
#Part("categories") List<String> categories,
#Part("name") String name,
#Part("price") String price
);
}
If this doesn't solve your problem, post the detailed log of your request, or take a look on this gist if you want full working example of image upload with progress bar
I am trying to send a JSON string as a request to my application. This is my code:
#RequestMapping(
value = "/mylink/upload",
method = RequestMethod.POST,
consumes ="application/json",
produces = "application/json")
public
#ResponseBody
List<Upload> upload(
#RequestParam(value = "hdfsLocation") String hdfsLocation
) throws Exception {
return S3HdfsTransfer.uploadFromHDFS(hdfsLocation);
}
I am trying to send a request with Postman. The method I use is POST, the header contains: Accept "application/json",Content-Type "application/json", the request body is the following:
{
"hdfsLocation" : "hdfs://145.160.10.10:8020"
}
This is the response I get. If I put the parameter in the URL, it works.
{
"httpStatus": 500,
"appErrorId": 0,
"message": "Required String parameter 'hdfsLocation' is not present",
"trackingId": "8c6d45fd-2da5-47ea-a213-3d4ea5764681"
}
Any idea what I am doing wrong?
Thanks,
Serban
Looks like you have confused #RequestBody with #RequestParam. Do either of following :
Pass the request param as a request param(not as a body). Like, (encoded)
http://example.com?hdfsLocation=http%3A%2F%2Fexample.com%3FhdfsLocation%3Dhdfs%3A%2F%2F145.160.10.10%3A8020
Replace the #RequestParam with #RequestBody. If you are sending a body, don't send it along with request param. Those are two different things.
I guess you over looked :)
Shouldn't it be #RequestBody instead of #RequestParam?
Also, even after using #RequestBody, the whole of the JSON string:
{
"hdfsLocation" : "hdfs://145.160.10.10:8020"
}
will be the value of String hdfsLocation and not just the hdfs url. Hence, you'll have to JSON parse that JSON by yourself to get just the hdfs url.
I'm having an Encoding problem when trying to consume an Arabic json message, however when producing the json in a get method I get the message right here is the code:
#Path("/json")
public class HelloJson {
#GET
#Path("/get")
#Produces("application/json; charset=UTF-8")
public Track getTrackInJSON() {
Track track = new Track();
track.setTitle("الليله");
track.setSinger("عمرو دياب");
return track;
}
#POST
#Path("/post")
#Consumes("application/json; charset=UTF-8")
public Response createTrackInJSON(Track track) throws UnsupportedEncodingException{
String result = new String (("Track saved : " + track).getBytes(), "UTF-8");
System.out.println(result);
return Response.status(201).entity(result).type("text/plain; charset=UTF-8").build();
}
}
you can try this webservice on the following link:
http://java7learning-khalidspace.rhcloud.com/rest/json/get
if asked for authentication use username admin and password admin
this link will return you a json with Arabic values without any Encoding problems.
now take this json message and use it in the post method using the following link:
http://java7learning-khalidspace.rhcloud.com/rest/json/post
you can use the post method using the webservice tester from eclipse or any other webservice just insert the content-type=application/json and authorization = Basic YWRtaW46YWRtaW4= as request headers and but the json in the request body.
the post method will return a massage with the arabic characters as "????"
please tell me what I'm missing and thanks for help.
Already have you tried to send them with the escaped characters?:
{
"title" : "\u0627\u0644\u0644\u064A\u0644\u0647",
"singer" : "\u0639\u0645\u0631\u0648 \u062F\u064A\u0627\u0628"
}
I get with this way using SoapUI and your http://java7learning-khalidspace.rhcloud.com/rest/application.wadl:
Track saved : Track [title=الليله, singer=عمرو دياب]