Storing Image Uploads Directly to Amazon S3

When your web application has to manage large amounts of images, you have to be mindful of the impact it has on your server. Not only will it consume valuable local storage, but it can impact the performance and have a financial cost.

On a project focused on users uploading profile images, I implemented the solution on a React front-end. Here is the process workflow:

  1. Load the file uploaded
  2. Send the filename and filetype to the server
  3. Receive the signedRequest from your AWS credentials
  4. Deliver the image file with the signedRequest to S3 for storage

Import Required Libraries

import $ from 'jquery';
import axios from 'axios';

Load the image submit form with an event handler:

<form onSubmit={this.handleImgUpload.bind(this)} encType="multipart/form-data">
<input type="file" onChange={this.handleFile.bind(this)} />

</form>

Receiving the event with the file and then invoking the image upload handler

handleFile(event) {
const reader = new FileReader();
reader.readAsDataURL(file);
this.handleImgUpload(file);

Image Upload handler that will get the signedRequest and deliver the image to S3. 
Note: Here we show the unedited two request methods because originally $.ajax was having issues being able to be nested after it’s promise. We use the axios library to make the PUT request to S3 with the image file. It is recommended to refactor into a single method. The updated approach will be updated here when time permits.

handleImgUpload(file) {
// First Request to the server
const promise = $.ajax({
url: '/sign-s3',
type: "GET",
data: {
'file-name': file.name,
'file-type': file.type
},
dataType: 'json'
});
    // Promise returns with the signedRequest
promise.done(function(data){
var options = {
headers: {
'Content-Type': file.type
}
};
    // Upload the file with the signedRequest to S3
axios.put(data.signedRequest, file, options)
.then(function(){
_this.setState({
picLink: data.url,
signedRequest: data.signedRequest
});
});
});
}