Serverless video to gif converter and url shortener

TL;DR; version

This is a serverless implementation of video to gif converter hosted on AWS. It contains an example how various services interacts with each other. Frontend and backend are lambda functions with API Gateway behind CloudFront. Route53 hosted zone points to CloudFront distribution to ensure https. SSL certificate has been provisioned using ACM. User uploads and gif files are stored on S3. DynamoDB is used to store short url pointer to S3 object that contains gif file so signed url can be created.

Application is written using NodeJS with the help of serverless framework. Frontend is written using vanilla JavaScript without any external libraries involved.

Try it in production here.

Full source code can be found on GitHub. If you have any questions feel free to use GitHub issues.

Long version

Gif reactions are very popular these days on various messengers and social networks. Who doesn't like to post a cat gif occasionally?

cat

There is a whole bunch of sites offering video to gif conversion but most of them are bloated or requires registration so I decided to create one for myself and share it with the public. My motivation was to make something simple and was curious can I make it serverless? Apparently it was easier than I thought. This is not intended to be tutorial but guidance how this service has been developed. You can always look into source code provided or ask a question

Prerequisites

  • User must be able to upload video file then serve converted gif.

    Amazon S3 is an object storage service that offers industry-leading scalability, data availability, security, and performance. Can’t be better than that.

  • Create gif from video file

    FFmpeg is a complete, cross-platform solution to record, convert and stream audio and video.

  • Compute power for application

    AWS Lambda lets you run code without provisioning or managing servers.

  • Database for our url shortener because S3 creates very long download links.

    Amazon DynamoDB is a key-value and document database that delivers single-digit millisecond performance at any scale.

  • Provision certificate to serve trafic over https.

    AWS Certificate Manager is a service that lets you easily provision, manage, and deploy public and private Secure Sockets Layer/Transport Layer Security (SSL/TLS) certificates for use with AWS services and your internal connected resources.

  • Redirect http to https.

    Amazon CloudFront is a fast content delivery network (CDN) service that securely delivers data, videos, applications, and APIs to customers globally with low latency.

  • Store application settings securely.

    AWS Systems Manager Parameter Store provides secure, hierarchical storage for configuration data management and secrets management. You can store data such as passwords, database strings, and license codes as parameter values.

I will not explain all these services one by one. For that you can visit their websites, links are provided. I will mention just a few crucial things and if you have any questions feel free to ask. There are two complicated things here. If lambda is serverless, how can we install ffmpeg if it is not provided as part of the environment itself? This is where lambda layers jumps in. You can compile and upload your binaries with lambda code of course. That is a valid option. But what if you need to share those binaries among multiple functions? Layers can help you to do so. Lambda layers are also great because you will exclude heavy binaries from deployment packages. You will deploy only your source code while layer will sit independently on your environment.

I was too lazy to create my own layer instead I have used one already created by Gojko Adzic and shared on AWS serverless pub directory.

Second problem is that S3 secure download links can be more than 1000 characters long. How can we make this better and create short links like other sites do? If you are serving your website and content from S3 bucket you can use S3 redirections without too much effort.

Other solution which I used in this project is to save object prefix and short unique id. Lazy as usual I didn't write my own unique id generator but used existing one. You can find it here.

So the last thing left here is how can we intercept this short urls then redirect to actual file? For that purpose we can use API Gateway proxy+ strategy. If API Gateway is unable to find route that client is requesting it will execute endpoint set with proxy+. Check this serverless.yml snippet:

  get-file: 
    handler: functions/get-file.handler
    events: 
      - http: 
          cors: true
          path: /{any+}
          method: get

This tells API gateway to catch all unknown routes. From this point it's easy to find coresponding DynamoDB document, create secure link to actual file then return redirection response from lambda:

  const signedUrl = await getSignedUrl('getObject', convert_bucket, Item.data);
  return {
    statusCode: 301,
    headers: {
      Location: signedUrl
    }
  }

Having all these things in place it's pretty straightforward to write code. "get-upload" function is our frontend. In order to use ffmpeg layer inside our "convert" function we need to add layer arn to our serverless.yml:

  convert: 
    handler: functions/convert.handler
    layers:
      - arnlambdaACCOUNT_IDffmpeg:1
    events: 
      - http: 
          cors: true
          path: convert
          method: post

Full source code can be found on GitHub. If you have any questions feel free to use GitHub issues.

Try it in production here.