Building a URL Shortener with GitHub Actions, Serverless Framework, and AWS Function URLs

David Llerena
Globant
Published in
6 min readJul 14, 2022

Introduction

Have you ever wondered how to deploy and maintain your solution into AWS with the minimum overhead? This article will show how to configure an environment for fast code deployment while building a solution for getting a short URL.

The following sections we will review in this article:

  • What is a URL Shortener
  • First steps
  • Hello Lambda with Serverless Framework
  • Automation with GitHub Actions
  • Creating the solution
  • Adding an alias record in Route53 (optional)
  • Conclusions

What is a URL Shortener

It is a tool that creates a string of random numbers and characters to replace the original URL, considerably reducing its actual length.

This article aims to create this tool while achieving as much automation as possible during its development cycle and demonstrate the use case of some AWS services.

First Steps

Let’s start by creating a package.json with:

npm init

Next, let’s add the necessary dependencies to create a lambda using typescript in our package.json file.

Don’t forget to install these newly added dependencies with:

npm i

Hello Lambda with Serverless Framework

Now let’s create a serverless.yml file where we will define our AWS resources as Infrastructure as Code. If you want to learn more about Serverless Framework.

Create a file named handler.ts, with this boilerplate code to make a hello world lambda.

It is time to push our code into our repository.

git add .
git commit -m “Create boilerplate lambda”
git push

Now we can start testing our lambda if we configure our AWS credentials with aws configure and deploy our code with the command serverless deploy, but before we do that, let's automate this process using GitHub Actions.

Automation with GitHub Actions

GitHub Actions makes it easy to automate all your software workflows with Continuous Integration and Continuous Delivery. Build, test, and deploy your code right from GitHub.

In our Github repository, click Settings on the left bar side, select Secrets then Actions. In the Actions secrets window, select New repository secret.

Create two secrets named AWS_KEY and AWS_SECRET, respectively. Here we will add our AWS Access Key ID and Secret Access Key. If you want to learn how to obtain these values, check this documentation.

Select Actions on the upper bar, in the Actions screen, select Set up a workflow yourself.

Clear the pre-defined template and add the following snippet. This snippet will use our previously defined secrets to authenticate and configure the necessary environment to deploy our resources into AWS.

Name the file whatever you want, commit and push. Be sure to git fetch and git pull this file into your local repository. The next time we make some change in our code, it will trigger a deployment pipeline which will create our lambda in AWS.

❗ Note: If Actions won’t activate, check the branch specified in “branches” in you deploy.yml file

branches: - master

After the pipeline finishes deploying successfully, let’s check our newly created resource in AWS.

Hello Lambda in AWS

Creating the solution

Since our CI/CD integration is working correctly, let’s start coding our URL-shortener solution. First, we need to create three variables that will help us define the name of our bucket, a domain, and the name of our application. For this example, I’m going to use the following values:

You can add any domain that you want; for the sake of the example, I will use a Route 53 domain that I had registered. If you don’t have a domain, you can use the S3 endpoint of the bucket that we will create as the value for the variable DOMAIN. TheS3_NAMEvariable, you can also write any name. However, I will use the domain’s name to register the s3 endpoint of this bucket under Route 53 as an Alias Record. For the value of the variable APPLICATION_NAME, name it the same as you defined in the service field of the serverless.yml file.

Creating Additional Resources

Now we proceed to modify our serverless.yml, where we are going to create a DynamoDB table named atomic_counter , an S3 Bucket with some rules, some IAM roles to give our lambda access to these resources, and we are going to change our hello lambda that used ApiGateway to a Function Url.

Let’s define our added Parameter Store variables to use in our code. You can define the region where your variables are located. In this example, our variables are in us-east-1. The variable value should read as:

As we reference, some of these values on the same serverless.yml file.

Change the handler and the event of our lambda to type url, which will create an http endpoint with a url that we can use to send a POST with the information that we need to process. You can custom the cross-origin resource sharing to whatever suits your needs.

Using Function URLs suits our use case since we don’t need to create a complex REST API. We only need an HTTP endpoint that we can use in a front-end view.

Next, create a DynamoDB table that will be used as an atomic counter and set an index called name.

Create an S3 bucket, which will have public access, and it will serve as a static website host. We also will need a Lifecycle rule as our service will work as a redirection of the objects we will create in our bucket. We would like to expire old links that we no longer use.

Finally, let’s give access to our lambda through IAM policies, these policies will provide access to put and update data into our s3 bucket and dynamo table.

In our handler.ts, we need to check the original inbound URL with a regex function. If the given URL doesn’t have a prefix, we append the string http://. Otherwise, the WebsiteRedirectLocation function will throw an error. Next, we get the number in the DynamoDB counter, which we will encode into a shortened string. We write a zero-length file out to our S3 bucket with the appropriate metadata that will serve as a path that redirects to the desired URL. Lastly, we return the shortened URL.

Before we push and deploy these resources, let’s update our package.json, with some libraries, like uuid, which will create a string with base62, to randomize the created URL.

After our actions pipeline finishes deploying, create a register in the atomic_counter table with the value of 1 and the application’s name, which we will use as an encoded string.

Adding an alias record in Route53

Let’s wrap up by creating an alias record of our s3 endpoint in Route 53, which will be used as a domain response of our url-shortener service.

Test our endpoint, by sending an URL that we like to short, and voilà! We completed our url-shortener.

Conclusions

While there may be different ways to create a URL shortener, I chose this stack of technologies for the following reasons: Serverless framework for its development speed, automatic scaling, and lower runtime costs. AWS for its reliability and different tiers of services. GitHub Actions for its ease of use and set up to deploy with various programming languages and cloud providers.

--

--