Creating an Image thumbnail generator using Vue, AWS, and Serverless (Part 4) — The Finish
In part 3, we created a lambda function that resized our images, tested it in Docker, and then deployed it. In this final part, we’ll bring everything together by showing the uploads in the Home.vue component and creating a route to show each upload’s thumbnails. To do this we’ll:
- Create an Upload component that will be render an individual upload’s thumbnails
- Create a new route for our router that will render the Upload component
- Create a List component to show the uploads
- Modify the Home component to include the list component
Creating the Upload Component
Before creating the upload component, we’re going to need to write a helper function in the aws.js
file that will get all thumbnails based on the upload’s key. Here’s what the updated aws.js
file looks like:
First, remember to add the name of your thumbnailBucket
to the config/development.json
and config/production.json
files. Next, we’ll create a new S3Bucket object just like we did for the upload bucket. Lastly, we’ll create a function called getThumbnails
which will get all of the objects in the thumbnail bucket that have the same prefix as the upload.
The upload component will take the parameter passed into the URL (through the route which will be created in the next step) and use that to get the applicable thumbnails. Here’s what it looks like:
When the component mounts, it calls getThumbnails
from the aws.js
file we just updated. Notice on line 26 that we have to do a bit of regex magic to remove the file extension from the key.
Creating a New Route
This is pretty straight forward — we’ll import the new upload component and then configure a route to point at it. Simple enough. Here’s the updated router/index.js
file:
Now, in the next step, we’ll create a list component that will render each upload. That upload will use a special <router-link>
component that will point to this route. When the route resolves, it will render the upload component into the <router-view>
.
Creating The List Component
Here’s the list component:
List
is passed in a boolean prop called isUploading
which will be explained when we modify the UploadForm
component. For now, know that the value is true when we have initiated an upload and false when the upload has completed. When List
mounts or when the value of isUploading
changes from true to false, we call getUploads
which causes List
to re-render. Effectively, the list refreshes every time we upload a file (or several files).
In the template, we loop through each upload and render a <router-link>
component. When we click on the upload in the UI, it will render the upload route we just created and render the thumbnails for that upload!
Modifying the Home and and UploadForm Components
We need to add the List
component to Home
and we need give the UploadForm
component the ability to modify some state on the Home
component. The way we do that is by passing a function to UploadForm
from Home
. Here’s the new Home
component.
Home
now has state in the form of isUploading
which gets passed as a prop to List
as mentioned above. We create a setUploadStatus
method and pass that as a prop to UploadForm
. setUploadStatus
is called when the form is submitted (sets isUploading
to true) and again when the upload completes (setting isUploading
back to false). When isUploading
goes from true to false, List
re-renders!
Here’s what the new UploadForm
looks like:
On line 29 we give UploadForm
its prop, which is the setUploadStatus
method we defined in Home
. On line 42 we call it which causes isUploading
on the Home
component to be set to true, which re-renders Home and passes isUploading
to list. On line 46, when the upload is complete, we set isUploading
to false which causes List
re-render, which in turn will render all of the new uploads!
Now, this whole process of setting state on a parent component from a child component is a bit confusing. In a bonus tutorial, I’ll replace the whole thing with a Vuex store that will manage all of the application state for us!
Deploying
Okay, now its time to deploy! We’ve already deployed the Lambda function and that hasn’t change since part 3. We need to rebuild the application and then sync it to the S3 bucket that hosts our application. All you need to do is run npm run deploy
from the client directory.
Now you should be able to go to the provided endpoint of your S3 bucket an should see you thumbnail creator application, ready to thumbnail some stuff.
A Word About Security
Disclaimer: I’m not a security expert and there are probably better ways to do this. Please comment or send me angry emails if you know of some.
There are some basic things that we should probably do to our buckets to make sure only we can be putting and getting stuff. First, in the upload and thumbnail buckets, you want to modify the CORS configuration.
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin><URL OF YOUR HOSTED BUCKET HERE></AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
This means that only requests originating from your hosted site will be able to make GET and PUT methods. Also, we can modify the bucket policy to only allow getObject action from a specific referrer. To do this, you can use to policy generator, which would look something like this:
Obviously replace the ARN with the ARN of your upload bucket, and the value in the conditional should be the URL of your hosted application followed by a trailing slash and a *
. The action selected in the dropdown is getObject
. In a bonus tutorial, I’ll show you how to use Serverless and IAM roles to make this even more secure, but for now this is a good start.
Wrap Up
Whew, we’re done! We created a neat thumbnail generator without really having to worry about anything that would be considered heavy devOps. The beauty of serverless is that its really very easy to create and manage your AWS resources. The beauty of Lambda is that you only have to pay for compute time. Without Lambda, we’d have to have a constantly running server somewhere and that is expensive!