In my first guide, I want to show you how to build a Drag&Drop component inside your Vue.js application using vue Dropzone. This is the first part of the series on how to securely upload your files to an S3 Bucket from vue.js.
For uploading the images we are going to use vue-dropzone, this is a vue wrapper of the dropzone.Js library, which provides you the ability to easily upload multiple files to an API. With vue Dropzone, you can also indicate the upload status, show a file thumbnail, restrict to file types, compress images before uploading and many more.
To make the upload process more secure, I will either recommend using presigned URLs when uploading your images [to an AWS S3 bucket](to an AWS S3 bucket "Upload files to Amazon S3"), or first upload your files to your API and from there to AWS.
This two approaches will improve the overall security of your application and your AWS account since your sensitive login info is not saved inside your frontend where it could be easily exploited. Instead, it is saved in your backend application where an attacker could not access it.
To provide you a better overview this article will be split into four sections.
In Section One, I will describe how to set up the UI. If you have the same Tech Stack as I have you can follow the complete list, but if you use something different you can just visit the parts which are relevant for you.
In the last section, I will tell you how to access your images in a fast way with AWS CloudFront.
The Images are going to be uploaded using dropzone.js, this is an amazing js library providing feature-rich drag&drop functionality with upload status, etc. in no time.
Dropzone.js
Step 1: Install and setupI will use the vue wrapper of dropzone, called vue-Dropzone.
First of all, we are adding vue dropzone to our project.
npm install vue2-dropzone
After the installation, you have full access to the dropzone.js functionality and it could be imported like any other vue-component into your vue App. You can use vue dropzone like any other plug-in in your nuxt js app. In the next step I will show you how to use dropzone.js to upload images and other files from your vue app.
Step 2: Using dropzone.js in your vue app
Next, we will set up the dropzone component, this should look something like in my Thumbnail Image.
If The Image was uploaded successfully by dropzone.js, it will be displayed like on the left, with the image name on hover.
Since we do not allow duplicated images on our S3 Bucket, adding the same Image twice will lead to an error (right), the image will be marked and on hover, the error message will be displayed.
Bellow you can see the code of our vue image upload component using dropzone js.
<template>
<div>
{{ label }}
<vue-dropzone
id="drop1"
ref="myVueDropzone"
:options="dropOptions"
@vdropzone-sending="appendLocation"
@vdropzone-success="handleResponse"
></vue-dropzone>
</div>
</template>
<script>
import ImageRepository from "../../Repository/ImageRepository";
import "vue2-dropzone/dist/vue2Dropzone.min.css";
import vueDropzone from "vue2-dropzone";
export default {
name: "dropZone",
components: { vueDropzone },
props: {
label: {
type: String
},
location: { type: String, required: true }
},
data() {
return {
selectedImages: [],
files: new FormData(),
baseURL: "youApiUrl",
dropOptions: {
url: baseURL + "yourEndpoint",
addRemoveLinks: true,
maxFilesize: 3,
accept: function(file, done) {
console.log(file);
if (
file.type.toLowerCase() != "image/jpg" &&
file.type.toLowerCase() != "image/gif" &&
file.type.toLowerCase() != "image/jpeg" &&
file.type.toLowerCase() != "image/png"
) {
done("Invalid file");
} else {
done();
}
},
headers: {
"Cache-Control": null,
"X-Requested-With": null,
withCredentials: true
}
}
};
},
methods: {
appendLocation(file, xhr, formData) {
formData.append("path", this.location);
},
handleResponse(file, response) {
console.log(response);
var Image = {
key: response.key,
imageId: parseInt(response.id),
bucket: this.location
};
this.selectedImages.push(Image);
this.$emit("input", this.selectedImages);
},
}
};
</script>
In the above code, we first import the vue dropzone component and display a label given as a prop above it.
The options passed to the component are defined in the dropOptions object. The next and last step is to adapt this options to your needs.
Step 3: adapt dropzone.js options to your needs
With this options set, our drag&drop file upload component will send a formData Object to the given URL, and got remove links to delete uploaded images again. The accept property could be used to define the accepted file types via this filter function, with maxFileSize we are not accepting files bigger than 3MB. The headers are set according to the needs of the API.
You can also intercept Dropzone js at different stages and execute additional code. For example, I'm appending the location where the image should be saved to the request, by simply listening to the @vdropzone-sending event. Again you can find the whole list of supported events in the dropzone.js documentation.
Before uploading your images, make sure to compress them. I would recommend compressor.io. Currently, I‘m working on auto-compressing my files on Amazon S3. Stay tuned to see also this guide.
conclusion
This was the first part of my series on how to securely upload files to Amazon S3 from you're Vue Js frontend. In the next part, I'm going to explain how to set up an Amazon S3 Bucket to store the images in.
To test your file upload component I would strongly suggest using cypress. I wrote a guide about testing this component here.
I hope I could help you to upload your files from vue and save you some time, if you got feedback just contact me in the say hi section. If I could help you, you can support me by buying me a coffee.
Happy coding,
Alex