Java – Use Retrofit2 to upload files to the AWS S3 presigned URL

Use Retrofit2 to upload files to the AWS S3 presigned URL… here is a solution to the problem.

Use Retrofit2 to upload files to the AWS S3 presigned URL

I’m trying to upload a file to Amazon’s S3 using a presigned URL. I get the URL from the server that generated the URL and send it to me as part of a JSON object. I get the URL as a string 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 it to Retrofit2, it modifies the string that tries to turn it into a URL. I’ve set encoding=true to fix most of the issues, but haven’t quite solved it yet. I know String works as-is. I’ve tried it in Postman and got a successful response.

1st I tried putting the string (except what I removed as baseUrl) into the path as a whole

public interface UpdateImageInterface {
    @PUT("{url}")
    Call<Void> updateImage(@Path(value="url", encoded=true) String url, Body RequestBody image);
}

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

Apart from ‘?’, this is mostly valid (after “ImageName”) to “%3F”. This results in Bad Request/400.

My next attempt was to create a query with Retrofit2 and dump the entire string (containing 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);
}

Call 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 will get ‘?’ Render correctly, but all “&” is changed to “%26”

Finally, I tried passing the entire string in baseUrl() but gave IllegalArgumentException because there was no “/” at the end.

I

know I can parse presigned URLs for multiple queries and combine them in Retrofit2 because the queries should be done, but I want to avoid this processing.

Restate the question:

Is there a way to easily (without heavy string parsing) to S3 using pre-signed URLs using Retrofit2?

Solution

With the help of colleagues, this is the solution.

public interface UpdateImageInterface {
    @PUT
    Call<Void> updateImage(@Url String url, @Body RequestBody image);
}

Call 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 information about @Url (class URLs) &
baseUrl() (class Retrofit.Builder).

MediaType is a library in a class in OkHttp that is often used with Retrofit (both from Square). Information about constants passed to the parser method can be found in Javadoc.

Related Problems and Solutions