Serverless website using Angular, AWS S3, Lambda, DynamoDB and API Gateway

Serverless architecture – you might have already heard this term. But have you tried to build one? And do you understand what Serverless architecture really means? Typically a web application requires an infrastructure to host Web Server, Application Server, and Database Server. Traditionally organizations had either their own datacenters or rented servers to manage such requirements. With Cloud – Pay as you use model has gained a lot of popularity. The headache of managing physical infrastructure has been moved to vendors like Amazon, Microsoft, and Google. Given all that, your team is still responsible to provision, monitor and manage the servers.

With Serverless Architecture, Organizations gain total freedom from managing infrastructure and can focus on building functionality. The need for scaling, patching and provisioning servers is opaque to the development team, rather it is a responsibility of a Cloud Vendor. In this article, we will build a Serverless architecture with a Dynamic Web Application using Angular, AWS S3, Lambda, DynamoDB, and API Gateway.

Prerequisites

To proceed with building a Web Application, you must fulfill following prerequisites.

  • AWS Account – You can opt for free tier account available from AWS. Even if your free tier eligibility has expired, the technologies used in this article won’t cost you except AWS S3. In case you don’t have an account, you can sign up for a free account at AWS Site.
  • NodeJS – Utilities will be leveraged to manage UI Project.
  • Angular CLI – Required for generating, building Web User Interface.
  • Microsoft Visual Studio Code – For editing Web pages and scripts.

Installation procedure for NodeJS and Angular CLI can be found here.

Serverless Architecture

Here is the preview of what we are going to build.

Serverless Architecture

Serverless Architecture

The web application will consist of pages to add, delete and list user profile. We will use Angular to develop the web pages. Angular is a client-side technology thus we can host it on S3 buckets using static website hosting feature. Pages will be directly served to end user without any need of server-side processing.

For storing the user information we will utilize AWS DynamoDB and the server side operations will be performed using AWS Lambda. As you might be aware that AWS Lambda doesn’t require dedicated EC2 or compute instances to be exclusively managed. AWS managed services will ensure spinning up required environment for hosting the code and also it will take care of scaling requirements. Finally, to make the Lambda functions available to Angular pages, we will make use of API Gateway. API Gateway comes with a host of features including API designer, test creations, staging code etc.

Data Storage using DynamoDB

A database provides persistence mechanism for storing durable data. AWS comes with a bundle of options like AWS Relational Database Service (RDS), AWS DynamoDB, Amazon Redshift etc. We will use DynamoDB database in this example but you are encouraged to explore other options as well.

If you have already signed up for AWS account, look for DynamoDB option listed under Database section. If you are accessing DynamoDB service for the first time, you will be prompted with a welcome screen and an option to create a table. Click Create Table button and configure it with following options.

Table Name: application_users
Primary Key: au_email

Keep the Default settings checkbox checked and click Create button. Within few seconds the database will be provisioned and there is no need to configure other columns. DyanamoDB is a document-oriented database and hence it can accept any structure for storing data. We will leave rest of the settings to default e.g. encryption, read/write capacity, TTL etc. Note that we have created the database in North Virginia region (Default).

Application Logic using Lambda Functions

It is time to write code to access the database. The usual practice is to write code in any of the programming languages like JavaScript, Java, C#, PHP etc. This code is later deployed on either web server/application server. Following such practice requires managing servers and identifying appropriate scaling requirements as per load. With AWS Lambda, developers focus on application logic rather than on infrastructure requirements. Lambda supports writing code in Java, PHP, Python, NodeJS, C# and Go. Though the options are limited, it is sufficient for most of the requirements.

Log in to the AWS console and locate Lambda from Compute section available under Services menu. If you are accessing Lambda Service for the first time, you will be presented with the Welcome screen. Click on Create Function button to proceed. You will be presented with options to choose from – Author From Scratch, Blueprints, and Serverless Application Repository. Make sure you have selected Author From Scratch. Configure the function using following settings.

Name: saveUserProfile
Runtime: Node.js 6.10 (as of writing this is the stable version available. You can choose any stable version.)

Choose Create a Custom role to create a new role in IAM. A new window will popup to configure the role. Enter following information

Role Name: lambda_user_manage_role

Leave the Policy Document as is and click on Allow button. Lambda Create screen will be displayed with the role name we just created. Click Create Function button to complete the wizard.

A new screen will be displayed with options as Designer and Function Code. We will make use of AWS SDK for Javascript to connect DynamoDB database.

var AWS = require('aws-sdk'), uuid = require('uuid'), 
    documentClient = new AWS.DynamoDB.DocumentClient();

exports.handler = (event, context, callback) => {
    var params = {
    Item : {
    "Id" : uuid.v1(),
    "au_first_name" : event.firstName,
    "au_last_name": event.lastName,
    "au_email": event.email,
    "au_gender": event.gender
    },
    TableName : 'application_users'
  };
    documentClient.put(params, function(err, data){
    callback(err, {
     "message":"User details saved successfully."
    });
  });
};

In above code, a DynamoDB client has been instantiated using AWS SDK. The client object has put method which accepts JavaScript object with record details and table name. The next argument is a callback function which either receives an error object in case of failure or the instance of data inserted.

Create following two more functions for listing and deleting users.

Name: listUserProfiles
Runtime: Node.js 6.10
Role Name: lambda_user_manage_role

var AWS = require('aws-sdk'),
    documentClient = new AWS.DynamoDB.DocumentClient();

exports.handler = (event, context, callback) => {
  var params = {
    TableName : 'application_users'
  };
  documentClient.scan(params, function(err, data){
    if(err){
     callback(err, null);
    }else{
      callback(null, data.Items);
    }
  });
};

Name: deleteUserProfile
Runtime: Node.js 6.10
Role Name: lambda_user_manage_role

var AWS = require('aws-sdk'),
    documentClient = new AWS.DynamoDB.DocumentClient();

exports.handler = (event, context, callback) => {
    console.log("Received event: " + JSON.stringify(event));
    var params = {
        TableName: 'application_users',
        Key: {
            "au_email": event['queryStringParameters']['email']
        }
    };

    documentClient.delete(params, function(err, data) {
        if (err) {
            callback(err, null);
        }
        else {
            var response = {
                "statusCode": 200,
                "headers": {
                    "content-type": "application/json",
                    "Access-Control-Allow-Origin": "*"
                },
                "body": JSON.stringify({ 'msg': 'User deleted successfully.' }),
                "isBase64Encoded": false
            };

            callback(null, response);
        }
    });
};

After completing the definition of DELETE request, locate DELETE method in API Gateway for users and click Method Request. Add email as new Query String Parameter under URL Query String Parameters.

Delete API request

Delete API request

Now open Service menu > Security, Identity & Compliance > IAM. The IAM role that we created in earlier steps doesn’t have permissions to interact with DynamoDB service.

Click Roles from the left menu and then Click the hyperlink displayed for the role lambda_user_manage_role. A Summary page will be displayed with various tabs including Permissions. Click Attach Policy button and search for AmazonDynamoDBFullAccess. From the options listed, tick the checkbox for AmazonDynamoDBFullAccess and click Attach Policy button. This will enable read/write access to the Lambda functions.

Expose API using API Gateway

Now that we have created Lambda functions to create, list and delete the user profile, it is time to configure API Gateway. The Lambda functions are not accessible over HTTP. We must create publicly accessible URL to invoke these Lambda APIs. API Gateway comes with developer friendly user interface to configure APIs. The editor provides a range of options to map API including EC2, Lambda, Proxy to another domain etc.

Click Services menu in the top bar and locate API Gateway in Networking and Content Delivery. A Welcome screen will be displayed. Click on Get Started button and a pre-filled editor will be displayed. Since, we are going to create our own APIs, choose New API option. Enter following details in the form.

API Name: User Management API
Description: API to manage user profiles
Endpoint: Regional

Click Create API button. A new editor will be displayed to define resources and methods. The API Gateway follows REST conventions and hence objects to be managed are treated as Resources, while operations on these objects are exposed as HTTP methods.

Click Actions button to pop menu items. Click on Create Resource menu item which will prompt for resource details. Enter following information

Resource Name: user
Resource Path: /user (This field will be auto populated based on resource name and hence leave it as is.)
Enable API Gateway CORS: Checked (This is required since we will be hosting UI application from the different domain.)

Click Create Resource button. A new entry will be added in Resources section below root path as /user. Make sure /user is selected in Resources section and then Click Actions button followed by Create Method. A list box will be displayed to choose an appropriate HTTP method. Choose POST as an option and click on tick mark besides the list. A new screen will be displayed to configure POST method details. Enter following information in the form

Integration Type: Lambda function
Lambda Region: us-east-1 (This should be the default selected unless you have changed a region. Also note that all our resources reside in that region.)
Lambda Function: saveUserProfile
Use default timeout: checked

Click Save button and a Permission dialog box will be displayed. Click Ok to proceed with API creation. Similar to POST method, create two more methods with the following information

List of User Profile

Integration Type: Lambda function
Lambda Region: us-east-1
Lambda Function: listUserProfiles
Use default timeout: checked

Delete User Profile

Integration Type: Lambda function
Use Lambda Proxy integration: checked
Lambda Region: us-east-1
Lambda Function: deleteUserProfile
Use default timeout: checked

Testing API

It is time to test our APIs before we invoke it from User Interface. Click on POST method under /users resources. A section will be displayed depicting the flow of how the request will be processed by the Gateway. Click Test link and enter following JSON data in the Request Body section.

{
    "firstName":"Paul",
    "lastName":"Witchkins",
    "email":"[email protected]",
    "gender":"male"
}

Click Test button and you should get a detailed log on the right side. Scroll to the bottom of the log and you should see a message similar to below.

Method completed with status: 200

Open DynamoDB interface from Services menu and a new record should be displayed under items tab for application_users table (if you don’t see the entry, hit refresh button available over the table). I leave the testing of other Methods to you as an exercise. You should be able to successfully execute all of them with the steps explained above.

Deploy API

We must deploy our API so that it can be accessed by the UI application. Click the /user link in Resources section and then click on Actions dropdown menu. We must enable CORS so that UI application hosted on S3 bucket must be able to access the API links. Click Enable CORS and a new form will be displayed. Leave the form defaults as is and click Enable CORS and replace existing CORS headers.

Now we are ready to deploy our API, click Actions dropdown menu. Then click Deploy API, a dialog will be displayed to enter deployment stage details. Enter the details as described in below image and click Deploy button.

Deploy API

Deploy API

Once the deployment is complete, you should see the URL to access our API. Copy this link and invoke our API from tools like Postman or SOAPUI. The link should be accessible over the internet and you should get the desired results.

Till now, we have seen how to create a DynamoDB table, Lambda functions to manipulate the data and use API Gateway to host our APIs. This completes the API functionality for our Serverless application. The part II of this article will focus on building User Interface using Angular and hosting it on S3 static website.

Be Sociable, Share!

2 Comments

Leave a Comment.