Building an AWS Serverless Web Application
Tags: aws, nodej, javascript, html
Published: 2022-10-26 07:23:47

## Introduction

AWS serverless offerings results in great development experience, reduce management overhead and deployed applications can benefit from various out-of-the-box features such as high-availability, performance and cost optimization.

AWS Lambda, API Gateway, DynamoDB are example of great serverless offerings and we have previously discussed that how AWS SAM simplify the process of creating and deploying serverless applications.

Today, we’ll take those learning and put together a backend of a very simple web application. This exercise will help us to build a foundation which we can later extend for more advance requirements.

Now, I am assuming that you are already familiar with AWS serverless offering as we will not cover the basics. 

## What are We Building

Following screenshot shows the finished application, where a simple webpage (HTML, JavaScript, CSS) is making ajax calls on regular interval to an API backend to fetch the data (random quotes) and display it on webpage.

![MainPage](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5osiacsxodcmjxikgvd1.JPG)

For this web frontend, we will be building a simple backend (NodeJS) consists of two lambda functions. We’ll have an AWS S3 bucket for file storage and we’ll also be using Amazon DynamoDB for data persistence.

Lets see these components one by one in the following sections.

**Data Input**

I have a json file (quotes.json) which contains quotes from different authors.

In our solution, we’ll have an S3 bucket (quote-json-data), where we/user will upload the json file. 

Here is how the data looks like

![QuotesText](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q0tso3k2lv4feqrjgvqt.png)

So once the file is uploaded to S3 bucket, we’ll wire the S3 event to trigger a lambda function (import function). This lambda function will read data from json file and then save it to a DynamoDB table. Once data is saved, the input json file is deleted from the S3 bucket by lambda function. Following picture shows the components for this part:

![Components](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oc59lxo3redz9y8hrlqu.png)

This concludes the data input part. Next, lets see how this data will be read.

**Data Read**

For this part, we will write another lambda function, which will read previously persisted quote data from DynamoDB table and we will make this data available via an API Gateway.

So a very basic HTTP Get action to read random quote and serve those to caller. Following picture shows these components added:


![Updated Components](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i4moyuwrjd387cco7y0s.png)

**Data Consumption (Web-page)**

Though this is not the focus of this post, but we will have a simple web-application with simple JavaScript function to make an ajax call to API endpoint to read the random quote data at regular intervals (every 12 seconds) and refresh on webpage:

![Data Consumption](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yoon22dvznkkrm6ozju3.png)

However, we’ll not use SAM template for this part. You can simply skip this part and use Postman e.g. to test the API.

So that’s our overall solution, lets see how to setup resources and deploy serverless function using SAM.

## Creating Resources in AWS

I’ve created a git repository for the SAM template and corresponding lambda functions code and static website assets. Here is how solution looks like in visual studio code:

![Solution](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kccf9j33kqiho8hycsvw.png)

We have two lambda functions defined in SAM template and corresponding code folders. Please check the sam-template.yaml file and code folders for more details.

Following picture shows Import function which is triggered when a new object is created in the S3 bucket (file upload). Note, that we are passing the DynamoDB table name as an environment variable, where our lambda function will store the data form json file:

![Lambda](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lv75r0yj54xiltggp9zx.png)

Next, for the API Gateway and corresponding lambda function (QuoteAPIFunction):

![API](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2xe9new78wgir0ld1ds8.png)

Notice that bucket-name is passed to this lambda function as environment variable, Access is given by Policies and you can check the Lambda function code in the source code folder from git repo.

Also in SAM template, DynamoDB table and S3 bucket (for json file) are defined as follows:

![SAM template](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mnd74hgyxcgi6mizu965.png)

As you can see that we are using same input parameter for S3 bucket and also for DynamoDB table.

## Deploying the Resources

The README file included with source code contains command:

![Commands](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1s7nzysbrkvk62sbox69.png)

We’ve covered these commands in earlier posts, following is the execution result of these commands:

**package command**

![package Command](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vpxk07pkw4p400lnbc1i.png)

**deploy command**


![deploy command](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x2h3hzh8492znofwti4l.png)

and if we go to CloudFormation console, can see the deployment status in more visual way:

![status updates](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o1010vusjn3zyx69f8c4.png)

At this point, all of backend AWS resources are created. However, there is still no data in DynamoDB table.

So, we can upload the quotes.json file to S3 bucket and see the workflow (trigger lambda function –> persist data to DynamoDB)


![quotes](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b4ek2m2tqyom4i1776j0.png)
once file is uploaded, we can check that if data is persisted to DynamoDB table:

![Dynamodb](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ageryfycfabn9fuwhz14.png)

Also, as part of SAM deploy, the Web API is also created and we can test if it returns the data by visiting the URL:

![Api](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m47ta1xh9isntwc36s1r.png)

and here is the data returned from the API:

![Data](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3akt5sp5buh5ugmabcnq.png)

Our backend solution is there and working as expected. We can now deploy a static website and can make ajax calls to the API endpoint to fetch the random quotes and display it on web-page.

## Static Website

Now I’ve covered static website hosting using S3 topic in another post you can check for more details.

Here, following code shows the JavaScript code making ajax calls to the API endpoint:

![JavaScript ajax](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9cvlzawi5np18ile8aid.png)

with this wiring in place, we can deploy the website. You can check the deployed sample application on 
[https://quoteapp.awsclouddemos.com/]

## Solution Design

Here is our solution diagram for reference:

![Solution diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oa5cndpute5k1aw0ahzk.png)

## Application Code

Now we haven’t discussed the backend NodeJS code and HTML site wiring in details. All the source code and SAM template are available on [this](https://github.com/jawadhasan/quotes-app) git repository. Application code itself is very basic and self explanatory. However, I’ll cover the application code parts in more details in a separate post as we progress.

## Summary

In this post, we build a basic AW Serverless Web Application backend using key AWS Serverless services.

We used AWS SAM to package and deploy our application code and create resources and setup their wiring. We can now reuse this template for similar applications or extend/change it as needed.

Let me know if you have some questions or comments. Till next time, happy coding.