Building a Serverless Web Application
Tags: aws, serverless, webdev, api
Published: 2022-12-12 10:03:13

When deploying a web application or anything in the cloud, these are the steps I try to follow to ensure that I have everything covered so as to create a sturdy infrastructure.

## 
**1. What is our AWS storage service?**

- We will instead use a database service.

**2. What is our AWS compute service?**

- Since we want a serverless service, we will be using **AWS Lambda.**

**3. What is our AWS database service?**

- For storing our data we will be using **Amazon DynamoDB.**

**4. What is our AWS network and content delivery service?**

**5. What is our AWS security, identity and compliance service?**

- We will use **Amazon Cognito** to manage user sign-in and sign-up.

**6. What is our AWS cost management service?**

- We will be tearing down our lab at the end so we don't need this(you can implement this in you architecture if you want to).

**7. What is our AWS management and governance service?**

## REQUIREMENTS

Before we get started , these are the requirements for this lab:

1. An AWS account(I am using resources within the free tier), this will allow you to create the IAM user in step 4.

2. VS code installed on you local machine(this is where I will be running my CLI commands)
_(NOTE: You can edit add VS Code ad your text editor for Git by running 
`git config --global core.editor "code --wait"`)_

[The link to this lab is:](https://aws.amazon.com/getting-started/hands-on/build-serverless-web-app-lambda-apigateway-s3-dynamodb-cognito/?ref=gsrchandson)

---

## **STEP 1: Hosting a static website with AWS Amplify, AWS Code Commit**

** ## What is AWS Amplify? **
-A complete solution that lets frontend web and mobile developers easily build, ship, and host full-stack applications on AWS, with the flexibility to leverage the breadth of AWS services as use cases evolve. It provides a git-based workflow for continuous deployment and hosting of full-stack web apps.

** ## What is AWS Code Commit? **

- We will configure AWS Amplify to host the static resources for our web application with continuous deployment built in. 

- All of our static web content which include HTML, CSS, JavaScript, images, and other files will be managed by AWS Amplify Console. Our end 
users will then access our site using the public website URL exposed by AWS Amplify Console and we don't need to run any web servers or use other services to make our site available.

1. While in the AWS Console, in services, go to AWS Amplify. Select a region (choose a region that can support all our resources , I choose us-east-1)

2. Create a Git repository, I decided to AWS Code Commit as per the lab(you also have the option to use GitHub, which I will use in a later project). In the services tab, search for AWS Code Commit console , click create repository, Input the name you want, and click create.

3. Make sure to create an IAM user with Administrator permissions that will allow them access to  Code Commit, also create their GIT credentials then click the link in step 4.

4. [Create Git credentials for HTTPS connections to CodeCommit](https://docs.aws.amazon.com/codecommit/latest/userguide/setting-up-gc.html#setting-up-gc-iam)

_(NOTE: On some versions of Windows, you might see a pop-up message asking for your user name and password. This is the built-in credential management system for Windows, but it is not compatible with the credential helper for AWS Code Commit. For this situation please follow these links [AWS documentation](https://docs.aws.amazon.com/codecommit/latest/userguide/setting-up-https-windows.html) and [Youtube](https://www.youtube.com/watch?v=E1GJqfIEJkM)otherwise you will keep getting error 403.)_

5. Now we will copy files from an S3 bucket to our local machine repository, these are our web app files.

```
cd myfirstserverlessapp  
aws s3 cp s3://myfirstserverlessapp-us-east-1/WebApplication/1_StaticWebHosting/website ./ --recursive
```
_(NOTE: Any commands to aws that we run from the CLI always start with the key word: **aws** )_

6. Now we will follow the git process for pushing files to a repository.

```
$ git status
$ git add .
$ git status
$ git commit -m 'new'
$ git status
$ git push
```

7. We now use AWS Amplify to deploy the code that we just pushed to AWS Code Commit.

- Launch the Amplify Console console page

- Click Get Started under Deploy with Amplify Console

- Go to New App on the top right and choose Host Web App.

![Hosting a new app ](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zimcmryhfqn7ioi0ocsp.png)

- Select Code Commit under Get started with Amplify Hosting.

- Select the Repository service provider used today and select Next.

- From the dropdown select the Repository and Branch  just create.

- On the "Configure build settings" page leave all the defaults and select Next.

- On the "Review" page select Save and deploy.

- The process takes a couple of minutes for Amplify Console to create the necessary resources and to deploy your code.

![Succeful deployment](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7bjdv8z2bdd3dsncgpnm.png)

---

## **STEP 2: Manage user accounts with Amazon Cognito**


 
**What is AWS Cognito?**

- It an AWS resource that lets you easily add user sign-up and authentication to your mobile and web apps. It also enables you to authenticate users through an external identity provider and provides temporary security credentials to access your app's backend resources in AWS or any service behind Amazon API Gateway.

- In this module, we want users to put in their details (i.e emails and passwords). Then Cognito will send a verification code via email to them, for authentication, which users can then put in the site and be verified/can also use the link in the email, then can be able to sign in.

- When users sign in, they enter their username (or email) and password. A JavaScript function then communicates with Amazon Cognito, authenticates using the Secure Remote Password protocol (SRP), and receives back a set of JSON Web Tokens (JWT). The JWTs contain claims about the identity of the user and will be used in the next module to authenticate against the RESTful API you build with Amazon API Gateway.
 
1. We will create user authentication using Cognito  User Pools in the backend to add sign-up and sign-in functionality to our application_(**Cognito** Identity Pools authenticates users through Facebook, Twitter or Amazon)_

- In AWS Cognito, choose **Manage your user pools.**

- The choose **manage your User Pools**. 

- Type in a name for the user pool and choose **Review defaults.**

- Then choose **Create pool**, and note down the **Pool Id.**


2. We will now add our app from step 1 to the user pool.

- In AWS Cognito, Pool Details page for our user pool, choose **App clients.**

- Choose **Add an app client**  and type in a name for the app client.

- Make sure to **UNCHECK** the **Generate client secret** option.

- Choose **Create app client** and note down the **App client Id** for the application.

3. We will now update the website config.

- We will update the **/js/config.js** file. First we will open the file in VS code(it's one of the files we cloned from the S3 bucket in Step 1.5)

- We will update the file with saved values of **userPoolId** and **userPoolClientId** and set the region where we set our application in step 1. It should appear like this:

```
window._config = {
    cognito: {
        userPoolId: 'us-east-1_eAWejjXJF', // e.g. us-east-2_uXboG5pAb
        userPoolClientId: '5dd2aq9pj2akcfo7d2ehlnqqgc', // e.g. 25ddkmj4v6hfsfvruhpfi7n4hv
        region: 'us-east-1' // e.g. us-east-2
    },
    api: {
        invokeUrl: '' // e.g. https://rc7nyt4tql.execute-api.us-west-2.amazonaws.com/prod',
    }
};

```
- Save the file and push it to our Code commit repository which will automatically deploy it to the AWS Amplify Console i.e.

```
$ git status
$ git add .
$ git status
$ git commit -m "updated file"
$ git status
$ git push
```

4. We will verify that everything is working.

- Go to our **sign up tab/ register tab** and enter our details and sign up**(In later tutorials we will set up our user pool to user **AWS Simple Email Service** to send emails from our very own domain)**

- Follow the steps as you usually would for registering in other websites, it will give the image below. Not to worry, we will update the API next.


![API not configured](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q8zpgod30rghw3pvkmbv.png)

**

## STEP 3: Building a Serverless backend with AWS Lambda and Amazon DynamoDB.
**

**What is AWS Lambda?**
- AWS Lambda is a serverless compute service that runs your code in response to events and automatically manages the underlying compute resources for you. These events may include changes in state or an update, such as a user placing an item in a shopping cart on an ecommerce website.

**What is AWS DynamoDB?**
- Amazon DynamoDB is a fully managed NoSQL database service offered by AWS, designed to provide low latency and high performance for applications.

- We will now fulfill requests made by the application, which is done by the Javascript running in the browser which will need to invoke a service running in the cloud.

- You will implement a Lambda function that will be invoked each time a user requests a service. The function will select the object/item from the store, record the request in a DynamoDB table, and then respond to the frontend application with details about the item being dispatched.

1. Create an AWS DynamoDB table.

- Select DynamoDb from Services and the click **Create Table.**

- For the **Table name** enter _Bags_ ,and enter _BagsId_ for the **Partition key** and select String for the **key type**.(_ All these fields are case sensitive._)

- Check **Use default settings** and then choose **Create.**

- Scroll to the Overview section and record the **ARN.**

2. Now we will create an IAM role for our Lambda role.

- From AWS Services, select IAM, then select **Roles** then choose **Create Role.**

- For the role type , select **Lambda**, for permissions , choose **AWSLambdaBasicExecutionRole**, then choose next step.

- Enter the **role name** and choose **create role.**

- _(We now want to allow the role above to put items into our Dynamotable)_Choose the role that you just created , then on the **Permissions** tab, under **Add permissions** choose **Create Inline Policy.**

- Select **Choose a service**, then in the search box named **Find a service**, type in **DynamoDB** and select it.

- Choose **Select actions** , in the search box named **Filter actions**, enter _PutItem_. Then in the **Resources** section , select **Specific** option then choose the Add ARN link and paste in the ARN for the DynamoDB.

- Choose **Review Policy**.Enter _DynamoDBWriteAccess _for the policy name and choose **Create policy.**

3. Create the Lambda Function to Handle Requests.

- In this step we'll build the core function that will process API requests from the web application to dispatch the item(which is a bag).

- Select **Lambda** then click **Create function.**

- Keep the default **Author from scratch card** selected. Enter _RequestBag_ in the **Name** field.

- Select **Node.js 16.x** for the **Runtime**.Select _Choose an existing role_  from the **Role dropdown.**

- Select **our role name** from the **Existing Role** dropdown. Then click on **Create function.**

- Scroll down to the **Function code** section and replace the existing code in the **index.js** code editor with the contents of **requestbag.js.** Then choose **Deploy.**

4. We now test/validate out implementation.

- In the main edit screen for the function, select **Test** and choose **Configure test event** from the dropdown and then keep **Create new event** selected.

- Enter _TestRequestEvent_ in the **Event name** field then copy and paste the following test event into the editor and then **Save**:

```
{ 
    "path": "/ride",
    "httpMethod": "POST",
    "headers": {
        "Accept": "*/*",
        "Authorization": "eyJraWQiOiJLTzRVMWZs",
        "content-type": "application/json; charset=UTF-8"
    },
    "queryStringParameters": null,
    "pathParameters": null,
    "requestContext": {
        "authorizer": {
            "claims": {
                "cognito:username": "the_username"
            }
        }
    },
    "body": "{\"PickupLocation\":{\"Latitude\":47.6174755835663,\"Longitude\":-122.28837066650185}}"
}
```
-  On the main function edit screen click **Test** with _TestRequestEvent_ selected in the dropdown. Scroll to the top of the page and expand the **Details** section of the **Execution result** section. Verify that the execution succeeded and that the function result looks like the following:

```
{
    "statusCode": 201,
    "body": "{\"RideId\":\"SvLnijIAtg6inAFUBRT+Fg==\",\"Unicorn\":{\"Name\":\"Rocinante\",\"Color\":\"Yellow\",\"Gender\":\"Female\"},\"Eta\":\"30 seconds\"}",
    "headers": {
        "Access-Control-Allow-Origin": "*"
    }
}
```

**

## STEP 4: Deploy a RESTful API
**

- We will use **Amazon API Gateway** to expose the Lambda function you built in STEP 3 as a RESTful API. This API will be accessible on the public Internet. It will be secured using the Amazon Cognito user pool  created in STEP 2. Our statically hosted website will now be a dynamic web application by adding client-side JavaScript that makes AJAX calls to the exposed APIs.

- Our static website that we deployed in STEP 1, already has a page configured to interact with the API from this this step. The page at /bag.html has a simple interface for requesting a bag. After authenticating using the /signin.html page, your users will be able to select their pickup location by clicking a point on the map and then requesting a bag by choosing the "Request Bag" button in the upper right corner.