Serverless Computing: Freedom, Limitlessness, and Scale.

Effortlessly Set Up a Serverless Web App in Minutes — 💻 Web to Lambda🐑

In this article, we will go through a step by step guide to setting up a very simple serverless AWS (Amazon Web Services) based web app. “Serverless” computing, as the name suggests, allows developers to set up code (for apps, websites, IoT devices, etc) without having to worry about managing servers. All you need to do is upload your code and then that code will run in the cloud.

Note that the term “serverless” is actually a misnomer. Your code is still run on servers, but with “serverless” computing you don’t have to worry about managing those servers as a developer. You only need to be concerned with your function code, the code that carries out your business operations.

Developers traditionally manage servers to do back-end logic for code-based technology like apps. An example would be an app that can retrieve user data and update user data. This type of back-end computing is traditionally done with servers managed by the developers themselves, just like cave women and cave men💻🐒. On the other hand, with serverless computing, you only need to upload to the cloud small pieces of code for each function. For example, you can upload a small bit of code to retrieve user data, and a small bit of code to update your user data. These two Lambda functions are completely independent.

In our article we will be making a web app that has a single Lambda function. Before we start setting up our web app, let’s go over why we are even using this new cutting-edge serverless technology.

Serverless computing offers many huge advantages over traditional server-based computing:

  1. It’s cheaper. You only pay when code is run. If you have servers, you have to pay whenever your servers are running. Since apps usually run 24/7, that means you have to pay 24/7 if you are using servers, even though people might not be using your app at certain times of the day. Using serverless computing also greatly minimizes the amount of time you spend managing infrastructure. Using serverless infrastructure can save you a huge amount of time as a company, it can even potentially allow your company to have less employees. Not having to hire someone to solely focus on “dev ops” can save you a great deal of money.
  2. It’s scalable. If you have an app that uses serverless computing, and if you have one user, or one million users, you don’t have to have to make any changes, you just upload your code in the same way, and it will work. If you have servers, you need to worry about adding more servers if you have more users. If you only have one server, and one million users are accessing that server, that one server might not be able to handle all those requests. Also, if you have more than one server, then you have to worry about routing traffic properly among all those servers (i.e. load balancing). You don’t have to worry about these things when you are using serverless computing.
  3. It’s easier to work with. If you have an app, each action, which is done by a serverless function, has its own code. That code will only be for that one action (although it should be noted that different actions will probably have some shared code). Your serverless function for getting user data will be completely separate in its cloud deployment from your function for updating user data. You can modify the getter function without affecting the other already uploaded update function (and vice versa). This is great for teams of developers, Aanya can work on the get user serverless function, while Aditya works on the update user serverless function. Aanya and Aditya can upload their new function whenever they like without worrying about one affecting the other’s uploaded function.

Now, let’s get to building our serverless app! Below is a diagram of how it will work:

Developer Aanya sending an HTTPS request from her computer to trigger an AWS Lambda function.

The example in this tutorial below will be accessing a Lambda function from a single page web app (SPA). This Lambda function will scrape data from one of three websites. The data being scraped is the size of the website’s HTML file. Below is what the final result should look like:

This single page web app triggers a Lambda function that scrapes a website’s data (the size of the website’s HTML file). High quality version of this video here.

Click Here to Check out the AWS Cloudfront Hosted Live Demo!

(you will need an API ID and an AWS Region to make it work, read more to find out how to make it work with your own ID and region!)


Prerequisites for this tutorial:

Although this tutorial doesn’t require any coding, you will probably need the following:

Now that we have everything we need, let’s begin setting up our single page web app to access Lambda functions!


Step 1. Download the tutorial NPM package

First thing you will need to do is create a directory where you want to work. To accomplish this, you can just create a new folder on your computer. Go to that folder using your terminal or command line. You will then need to initialize an NPM project with the following command:

npm init

Then, just keep pressing enter until it stops prompting you for information. Next, install the NPM tutorial package with this command:

npm install web_to_lambda

We now have everything we need to create our serverless web app!

Step 2. Upload the Lambda Function

Before we upload our Lambda function, let’s first check out the actual Lambda function code to see what a Lambda function looks like.🔬

About the function:

The actual function logic is in the .POST function and it starts on line 38. This function code will be attached to a Lambda proxy integration of an API Gateway endpoint (this will be explained in more depth later). The function accepts and requires a website URL, this URL is accessed through the “websiteUrl” key in the “body” object. The “body” object is in the “event” argument object (see line 42). This URL is used to retrieve the size of the website. On line 48, the “websiteUrl” value gets passed in as an argument to the “getSizeOfWebsitePromise” function, this function is a Promise. The size of the website (in bytes) is then returned in an object and is stored as the value whose key is “sizeOfWebsite” (see line 66).

Overall how it will work is that you will make an HTTPS request from your browser with the specified website URL whose data you want to scrape (the website size). This request will trigger the Lambda function code to run which scrapes the data from the specified website and subsequently returns the scraped data of the website to your browser.

You may noticed that this is a Vandium wrapped Lambda function.

Why do I use Vandium with my Lambda functions?

  • It makes Lambda functions MUCH easier to write (and read). All I need to do is return a value or a Promise and Vandium will figure out all the mapping. If you are not using Vandium, then you must deal with the callback function, not cool😔.
  • It deals with the validation in a really nice way. As you can see, this HTTPS POST request endpoint accepts and requires ONLY the parameter “websiteUrl”. Using the “validation” object on line 12, I have added validation to ensure that the incoming request “websiteUrl” value can only be one of three strings, “https://lessonshop.net”, “https://vandium.io”, or “https://github.com”. Input validation is extremely important for keeping your app secure and functioning as expected. As with any type of system (digital or non-digital), components that accept external input are generally an attack vector and must be protected. By having strict rules on what is coming into your system, you can prevent people from attempting to tamper with your system by using malicious or unexpected input values.
  • It makes error handling much easier to deal with. You just need to put a “.onError” function at the end of your Vandium wrapped Lambda function and you can catch and deal with any errors that occur within your function. This allows you to easily have a single error catching function which you can use for every Lambda function (for example, you can put that error catching function in a common “utils” (utility) file).
  • Vandium helps in many other ways. Vandium makes it much easier to deal with headers being returned on API HTTPS requests(see line 27). Vandium has a system that makes it super easy to work with JWTs (check out my previous article on JWTs if you want to learn more about JWTs, JWTs are very useful!). Vandium has a very secure way of dealing with environment variables, and Vandium has event handlers for pretty much every type of Lambda function (e.g. DynamoDB triggers, CloudWatch triggers). Check out their Github for more details.

Upload the Function:

Okay, so we have done A LOT of talking about the function, let’s get to some action and actually upload the function already!

We will be uploading this function without any deployment tools. We are doing this for the sake of learning. I wouldn’t recommend doing this for your real code, but I think it’s important to know exactly what is going on when you do use a deployment tool like my brother #ac360's (Austen Collins/Serverless) The Serverless Framework, or my other brother #swaggyTJ’s (TJ Holowaychuk) Apex.(shout out to my serverless brothers and sisters👊🏿👊🏽👊🏻!)

Steps to uploading your AWS Lambda function:

A) Go to the NPM package’s directory. Assuming in your terminal or command line you are still in the same directory as the one created in Step 1, input the following command to go to the right directory on your computer:

cd node_modules/web_to_lambda/

You should now be in the root of the NPM package “web_to_lambda” that you downloaded before. Install the NPM modules for this module itself. This module only has one dependency, the “vandium” module. Run the following command to install Vandium (the only dependency):

npm install

B) Next you must zip up the files and folders you want to upload. In our example, you must zip the “index.js” file, the “node_modules” folder, and the “lambda_function_logic” folder. To zip the files, generally you can just select them all and right click, an option to “zip”, “archive”, or “compress” should appear. Here is a demonstration video on how to zip the files:

How to zip the appropriate file and folders. The leftmost directory in this video is the root directory of this project, the directory we created in Step 1.

C) Log in to you AWS browser console and go to the Lambda function section. (Here is a link to that page to make your life easier!😉)

D) Now that you are logged into your AWS account and you are on the Lambda function page, click on the “Create function” button. It’s the big orange button that says “Create function”, press on it, please.

E) Next, you have to fill out the basic information and create a basic role. For the “Name*” section, name your function whatever you want, it’s a free world, follow your heart and you’ll think of an appropriate name. Just remember that name, please. For the “Role*” section, select “Create new role from template(s)”. For the “Role name*”, once again, just follow your heart. For the “Policy templates section”, leave it empty. Next, click on the big orange “Create function” button.

Creating your AWS Lambda function with a basic role attached to it. You can name the function and the role whatever you like, just remember the name of the function, please. High quality version of this video here.

F) Now you must upload the actual Lambda function code to the Lambda function that you have just created (the Lambda function just has the default code attached to it right now). You need to upload the zip file you created in step 2-B.

This is the browser page for your uploaded Lambda function, you need to upload the zip file you created before.

Also make sure you hit the save button!

After you upload the zip file, press the save button. (The big orange button that says “Save”😵)

Congratulations, you now have uploaded your data scraping Lambda function, you are now a professional AWS developer! Let us move on to the next step, attaching your Lambda function to an API Gateway endpoint.

Step 3. Make your Lambda Function Accessible Through the Internet (with API Gateway)

In the previous step, we set up our Lambda function, but we still can’t access this Lambda function from any random computer or device that’s connected to the internet. To make this function accessible through the internet, we need to attach the AWS Lambda function to an AWS API Gateway endpoint. What API Gateway does is it creates a publicly accessible API with endpoints which can be accessed through HTTPS requests. An API is essentially a bunch of URLs (endpoints) which can be accessed through the internet with internet requests (HTTPS requests). When you attach a Lambda function to an API Gateway endpoint, you can trigger that Lambda function by making an HTTPS request to that endpoint. Let’s set up our API:

Steps to setting up your API Gateway and attaching our Lambda function to it:

A) If not already logged in, log into your AWS account and go to the API Gateway section. (Here is a link to that AWS section, don’t worry, I have your back, I’ll hold your hand every step of the way.😉🙌🏿🙌🏽🙌🏻)

B) Click on the “Create API” button. (The big blue button that says “Create API”).

To create an API, press the big blue button that says “Create API”

C) To create the API, fill in the name (whatever you want it be) and optionally the description of the API.

Creating the API, you can name it whatever you want, just remember the name.

D) Next, set up the API endpoint resource that we will be accessing. A resource is just an endpoint URL component that you will be using to access the function. We will be attaching our function to the “mega-website-size-get” API resource. To accomplish this you must click on the “/” under the “Resources” column on the left. Then click on “Actions”. A drop-down menu should appear, in that menu click on the “Create Resource” button. This should open up the “New Child Resource” section. In this section for the “Resource Name*” section, input “mega-website-size-get”, and for the “Resource Path*” section, input “{mega-website-get+}”.

Adding the “mega-website-size-get” resource that we will be attaching our Lambda function to. High quality version of this video here.

Make sure you check off the “Enable API Gateway CORS” checkbox, this is very important! After you input the required info and settings, click on the “Create Resource Button” (the big blue button that says “Create Resource”, this button creates the resource). Also related to CORS, going back to line 27 in our Lambda function file, there is a header that was set:

.headers({
    "Access-Control-Allow-Origin" : "*",
// VERY IMPORTANT: Required for CORS support to work
})

About CORS

This “Access-Control-Allow-Origin” header is required for you to make HTTPS calls to API Gateway from your browser. CORS stands for Cross-Origin Resource Sharing and it is about the rules related to making HTTPS requests from your browser. All you need to know for this example is that you need to put the above header in your Lambda function setup. Although if you would like to know more about CORS, check out the MDN Documentation on CORS for a very detailed explanation. Note that this easy addition of headers is only a result of the use of Vandium. Vandium makes it really easy to have a common headers object such as:

// constants.js (the common file, a constants module)
module.exports = {
    commonHeaders: {
        "Access-Control-Allow-Origin" : "*",
// VERY IMPORTANT: Required for CORS support to work
}
};
/*
the handler file
(like the index.js file in our example)
(see below for an explanation of what a handler is)
*/
const constants = require( <path to constants module> );
...
.headers(constants.commonHeaders )

About the handler of a Lambda function
The handler is the literal Javascript function part of the Lambda function. The file with the handler is the entry point where the code runs. By default, it is “index.handler”, which means in your “/index.js” file, you are exporting an object that has your Lambda function as a property with the name “handler”.

//\\//\\//\\How to Export your Handler//\\//\\//\\
exports.handler = vandium.api()... // Your lambda function here
// equivalently
module.exports.handler = vandium.api()... // Your lambda function here
// this also works
const objectToExport = {};
objectToExport.handler = vandium.api()... // Your lambda function here
module.exports = objectToExport;

It’s good practice to NOT put your main logic in your handler function, but to only have a reference to your logic. In our Lambda function, our main logic, which is getting the website’s size, is not in the index.js file, it is imported as the function “getSizeOfWebsitePromise” (line 5). The actual logic is stored in the file “./lambda_function_logic/get_size_of_website_promise.js”

Keep your core Lambda function logic out of the entry point file (i.e. the file that contains your Lambda function handler). This makes your function code much easier to read and to test.

While we are on the topic of best practices, here is another article I wrote about the usage of open-source code, especially in relation to AWS Lambda functions.

E) After you create the resource, you will be taken to the set up page for that resource, this is where you select the Lambda function you want to attach to that resource. For the “Integration type” selection, select “Lambda Function Proxy”. For the “Lambda Region” section, select whatever region you deployed your Lambda function in when you created you Lambda function in Step 2-D. For the “Lambda Function” section, select the Lambda function you created in Step 2-D. After you set all the required data, press the “Save” button. You will be prompted to give your API permission to execute this. When you get this prompt, press the big blue button that says “OK” on it.


Setting up our “mega-website-size-get” API resource. High quality version of this video here.

F) The next thing we need to do is deploy our API. Our API is not accessible through the internet just yet, but after we deploy it, it will be accessible through the internet. Go to the your API page that you were on before, the one that lists all the resources, and click on the “Actions” button. In the drop-down menu, select “Deploy API”. You will be prompted to choose a stage. Click on the selection for the “Deployment stage”, and select “[New Stage]”. For stage name, input “ultra”. For the “Stage description” and “Deployment description”, you can put whatever your heart desires. Then press the big blue “Deploy” button.

Deploying our “ultra” stage for our API. High quality version of this video here.

After our stage has been deployed, we should be in the “ultra Stage Editor”. Take note of the “Invoke URL” displayed on this page.

You will need to extract the API ID, and region from this Invoke URL. See below for how to get these values.

The Invoke URL for the API I deployed is:

https://h0shm3xvob.execute-api.us-east-1.amazonaws.com/ultra

Please take note of your API ID, this is the value between “https://” and “.exucute-api”. So for my API, my API ID is “h0shm3xvob”. Also take note of your AWS region, this is the value between “exucute-api.” and “.amazonaws”. My AWS Region is “us-east-1”.


Congratulations, our API has been deployed and is now accessible through the internet! Now for the fun part, let us access our API from our web app.

Step 4. Set Up your Web App

You now have two paths to choose from🌴🐫:

Path 1, Step 4 — Shortcut:

Go to the live AWS Cloudfront hosted demo site, input the API ID and AWS Region that you took note of in step 3-F. Then go straight to Step 5.


Path 2, Step 4 — Set Up Your Own Web App:

Our web app is contained in a single html file. This file is in the NPM package we navigated to in step 2-A. In this directory there is a directory called “website”. In the “website” directory there is a file called “index.html”. Simply find that file in your file system (e.g. your Finder on a Mac, or through My Computer on Windows). Drag and drop this file into your browser and the site should be up and running.

Running our Single Page App (SPA). High quality version of this video here.
Note about the about the actual code for this web app (i.e. the code in the “/website/index.html” file only). This is not production level code (i.e. it is not suitable code for a business or a company), it is code written for a demonstrative purpose only. I would never suggest to write your production code like how I wrote this code. You should use tools like React.js or Angular to create your web apps. This file has way too many lines, and it uses global variables. I created the file in this way because it is really easy to run on your browser, you just need to drag and drop it. You can show this to your friends as a piece of code that has many anti-patterns. The “/index.js” and “/lambda_function_logic/get_size_of_website_promise.js” files DO have production level coding in them👍🏿👍🏽👍 (I will be adding unit tests for them in the near future)

The next thing we must do is input our API ID and AWS Region that we took note of in step 3-F.

Inputting our API ID and AWS Region into our web app. High quality version of this video here.

Congratulations, your API is all set up and all ready to go. In the next step we will press those big buttons and see what happens!

Step 5. Accessing your Lambda Function from your Browser

Now that our web app is set up and our buttons are ready to be pressed, press one of the big colourful buttons! The result should look like this:

Pressing the big colourful buttons! This accesses our Lambda function from our browser. High quality version of this video here.

If you got an error or if nothing happened, then there must have been a mistake in your set up process. Please go over the instructions again and make sure you have properly completed every step.

If you haven’t already, you can try out the live web app demo by inputting the API ID and the AWS Region of the API you deployed in Step 3-F. You can also try using the API ID and the AWS Region of the API that I deployed myself, it should yield the same results. My API ID is “h0shm3xvob”, and my AWS Region is “us-east-1”.

If you got the expected result, congratulations again! You have successfully set up your API gateway endpoint and have accessed it from your browser through the internet!

What is going on here? What do these big colourful buttons actually do?

There is one module import in our web app, it’s JQuery. When you press one of those big colourful buttons, the following HTTPS request is made with JQuery.

This Promise function accesses our “mega-website-size-get” API Gateway endpoint that we created earlier. When this endpoint is accessed, it triggers the Lambda function that we created which scrapes the size of the requested website. The Lambda function returns the size of the website to the API Gateway endpoint which then returns that value back to the browser which is then displayed for us.

You may have noticed that the first time you run this function, it takes slightly longer than it takes to run the function right after. This is because the Lambda function needs to “warm up”. If the Lambda function is “cold”, nothing is initialized and all the modules still need to be imported. After the function is “warm”, the modules have already been loaded and only the actual handler is executed, the modules are not reloaded again resulting in a quicker overall execution time.

Conclusion

In this article, we uploaded our Lambda function, attached it to an API Gateway endpoint, set up our web app, and triggered our Lambda function from our web app. This article merely skims the surface of what serverless computing is about. There is much more to learn, although this article is aimed at giving you a real fundamental understanding of what serverless computing is about so that you have a foundation of knowledge that you can build on. Serverless computing itself as a technology is in its infancy and only time will reveal to us its true capabilities.


LINKS AND 💻FUN STUFF🐑

Take or teach lessons. Take private software development lessons with me!

LessonShop.net — an entirely serverless app I built using the technology discussed in this article. Sign up in its early stage and start teaching or taking lessons! I (Mikey) offer private software development lessons through this web app. I can teach you React.js, Node.js, AWS, and Javascript. Private lessons with a good teacher are definitely the most cost effective and the quickest way to learn a new skill or to improve and refine your existing skills!

When you think lessons, think LessonShop!😉

Vandium for Lambda security

Vandium — The best tool (as discussed in this article) for wrapping your Lambda functions. Vandium provides a VERY important security layer and makes your code MUCH easier to read and to write.

DJ Khaled says “Another One”

Another One — A recent super duper article by Andrea Passwater about how to deploy a serverless function using “The Serverless Framework”. Shout out to #womenInTech/Women Who Code 👩🏿 🔬👩🏽 🔬👩🏻🔬

Apex & “The Serverless Framework” — Trendy tools for deploying your serverless code

“Web to Lambda” Tutorial Code —

  1. On NPM
  2. On GitHub

A Couple More Great Articles on Writing Lambda Code with Vandium —

  1. Writing less code with Vandium
  2. Unit testing with Vandium