Creating an Image thumbnail generator using Vue, AWS, and Serverless (Part 4) — The Finish

Ramsay Lanier
5 min readDec 7, 2017

--

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!

Ramsay is a full-stack JavaScript developer for a data analytics company in Springfield, VA. You can follow him on twitter or github. He likes when you do that.

--

--

Ramsay Lanier

I’m a senior web developer at @Novettasol and senior dad-joke developer at home.