Building a Complete Web Application Using AWS Services

Edula Vinay Kumar Reddy 14 Jul, 2023 • 15 min read

Introduction

When we start learning AWS, we usually learn bits and pieces of it, like some of the core services; working around the AWS console, we could create a new ec2 instance or an s3 bucket and upload something. But in most cases, we couldn’t combine all the services into an actual application. We knew different AWS services that we have been learning but couldn’t put them together into an actual usable thing, and if you’re feeling the same way, you’ve come to the right place. After finishing this article, you will be able to build a Password Manager application that is hosted in AWS, does its computation in the AWS server, user data will be sent to the backend server via an API Gateway, Final result will be displayed to the user in browser and also stores the data in an AWS database.

 Source: Created by Author

Ensure you have an AWS account and access to the console before moving further. Previous Knowledge of AWS is not necessary for this article; if you have some basic understanding already, that will be helpful if you don’t know, you should still be able to follow along as we are building our application. This article isn’t meant to be a deep dive into any AWS services, but it’s meant to tie them all together into a working application.

Learning Objectives

  • Create an end-to-end web application by integrating different AWS services.
  • Learn how to deploy and host web applications using AWS Amplify.
  • Learn how to create a backend server using AWS Lambda.
  • Learn how to use API Gateway for data transfer between frontend and backend components.
  • Learn how to store and retrieve data from the AWS DynamoDB database.

This article was published as a part of the Data Science Blogathon.

Overview of the Services and Application We’ll be Building

This article uses five AWS services to build end-to-end web applications from scratch, as shown in the above image. We will create a Secure Password Manager application that generates and stores secure passwords by taking the name, length, and properties of passwords (capital letters, small letters, numbers, special characters) as input. This simple application ties together all the main components you would need to build a much larger real-world application.

What do we need to do to build this application?

  • We must create and host a web page that our users will navigate in their browsers.
  • We need a way to invoke the password generate functionality.
  • We need a way to do the computation that gives results.
  • We need a way to store the result, and we need a way to return the result to the user.
  • We need to handle the permissions of these services in AWS.

Creating and Deploying a Live Webpage Using AWS Amplify

In AWS, there are actually several ways you could do this. We will choose AWS Amplify; with Amplify, we can build & host websites. It is a great service, particularly if you’re a front-end developer.  We will create an HTML page and then use Amplify to deploy and host that web page. Let’s do that now. Below is a simple HTML code that displays the name of our article when we open it.

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title> Secure Password Manager! </title>
</head>
<body>
    Creating an End-to-End AWS Application.
</body>
</html>

Step 1: Save this code with the name index.html and zip this file. Now we are going to deploy this in AWS Amplify. Go to the AWS management console and search for AWS Amplify.

 Source: Author

Step 2: We want to host the web app here, so select Amplify Hosting.

 Source: Author

Step 3: We don’t have a Git provider, so select “Deploy without Git Provider” and continue.

 Source: Author

Step 4: Give a name of your choice to the application. I am going to give mine as “PasswordGeneratorFrontend”. Give an environment name. Select drag and drop & grab that zip file we created earlier, and click save and deploy.

 Source: Author

Now you’ll see deployment is successful, and you will get the link to the hosted webpage. You can also get to this link anytime by coming over to domain management in the sidebar.

 Source: Author

We have a live web page that users can navigate to in our application.

Setting up an AWS Lambda Service to do the Computation in our Application

As you might know, a lambda function is just a bit of code that runs in response to some trigger, for example when you upload a picture to an s3 bucket, that could trigger a lambda function to process the picture into a thumbnail or something like that it’s just a code or functions sitting out there in AWS that gets run when you need them. These are serverless, meaning that you don’t have to set up and manage servers to run the code; it just happens automatically behind the scenes for you. So, we’ll write some Python code and do the computations that we need.

Step 1: Go ahead to the AWS console and navigate to lambda.

 Source: Author

Step 2: Create a new function and select “author this from scratch,” which should be your default already, and then give a function name. Then select runtime environment, let us go with the latest available version of Python. You can leave everything else the same and click on create function.

 Source: Author

Step 3:  Now scroll down in your console, and you can able to see an editor to write code. We will place our python code in that editor. Below is our Python code:

import json
import random
import string

def lambda_handler(event, context):
    # Extract input parameters from the event object
    name = event['name']
    length = int(event['length'])
    req_capital_letters = int(event['reqCapitalLetters'])
    req_small_letters = int(event['reqSmallLetters'])
    req_numbers = int(event['reqNumbers'])
    req_special_chars =int(event['reqSpecialChars'])
    # Generate the password
    password_chars = []
    allowed="" #allowed characters
    # Include one character from each selected character set
    if req_capital_letters:
        password_chars.append(random.choice(string.ascii_uppercase ))
        allowed=allowed+string.ascii_uppercase
    if req_small_letters:
        password_chars.append(random.choice(string.ascii_lowercase))
        allowed=allowed+string.ascii_lowercase
    if req_numbers:
        password_chars.append(random.choice(string.digits))
        allowed=allowed+string.digits
    if req_special_chars:
        password_chars.append(random.choice(string.punctuation))
        allowed=allowed+string.punctuation
    # Calculate the remaining length for random characters
    remaining_length = length - len(password_chars)
    # Generate random characters for the remaining length
    password_chars.extend(random.choice(allowed) for _ in range(remaining_length))
    # Shuffle the characters to remove order bias
    random.shuffle(password_chars)
    # Concatenate the characters to form the password
    password = ''.join(password_chars)
    # Return the password in a JSON response
    return {
        'statusCode': 200,
        'body': json.dumps('Your password for '+name+' is: ' + password)
    }

The code is pretty simple to understand. We are just importing the JSON utility package and the Python random string libraries for generating random characters then we have got our lambda handler; this is common to all lambda functions, and here’s where we do most of the work.  As you remember that our user is going to pass the name, length, and properties of the password(capital letters, small letters, numbers, special characters) as input. We are grabbing those values from the event object and storing them in respective variables. Then we include one character from each user-selected set. Then we calculate the remaining length for the password, and based on that length, we generate random characters for the remaining length from user-selected sets. Finally, we are returning the result as a JSON object.

 Source: Author

Make sure you save this code (you can just do CTRL +S), and then very importantly, you also need to deploy it by clicking on the deploy button right there.

Step 4: Now, let’s test our lambda function to make sure that this function is working correctly. Click the little drop-down arrow near the test button and click on “Configure test event”.

 Source: Author

Step 5: Let’s go set up a test event; it lets us pass in some test data to make sure that the function is working correctly. Create a new event and give the event name. In the Event JSON, we will pass some random password properties. In my case, I gave the password length as 10 and selected all character sets(1-selected, 0-not selected). Scroll down and then click on save.

 Source: Author

Step 6:  We successfully configured the test event; now, we need to actually run the test, which we can do by clicking on the test button. As you can see, we got a status code of 200 and the result contains at least one character from all sets. So, our lambda function is working correctly.

 Source: Author

So far, we have a simple html page hosted using Amplify and a lambda function to implement our application functionality.

Creating an API to invoke the Password Generator Functionality

Next, we need a way to invoke our password generator functionality or basically invoke that lambda function. Our users obviously aren’t going to
go into the AWS console like we just did and run it, so we need a public endpoint or URL that can be called to trigger the lambda function to run, and for that, we’re going to use API gateway service, this is a core service in AWS that we can use to build our own API’s(application programming interfaces), whether those are http, rest or WebSocket API’s it’s really the perfect way to invoke a lambda function. Let’s create a REST API for our Lambda function using API Gateway.

Step 1: Go to AWS Console and search for API Gateway.

 Source: Author

Step 2: Create a new API by clicking on the create API button. Now go to the REST API section and click on the build button.

 Source: Author

Step 3: Now select REST and select New API, and then we need to give it a name. In my case, I am giving “CallPasswordGenerator”. You can leave everything else the same, and click “Create API”.

 Source: Author

Step 4:  We have an empty API right now, it was not integrated with any lambda function. Let’s do that now.  Over the sidebar, make sure you have resources selected, and then you’ve got the backslash selected, and then on the action’s menu, select create method. The type of method will be a post, as the user will send data to AWS and then click the little check mark beside the POST.

Step 5: For integration type, we’re going to use a lambda function, and we give our lambda function name and then click on save.

 image.png

Step 6: Now, one important thing is we need to Enable CORS or cross-origin resource sharing. So go to the actions menu and select “Enable CORS”.
It allows a web application running in one origin or domain to access resources on a different origin or domain because our web application
is running on one domain in amplify. Our lambda function will be running in another domain, so we need to be able to work across those domains or origins
that’s why we’re doing this.

 Source: Author

Just leave all the default values and click the Enable CORS button below.

 image.png

Step 7: Let’s deploy the API so that we can test it out. Go to the actions menu and select Deploy API. We’ll need to set up a new stage here because you might have different stages for dev, test, and production. Click on ‘Deploy’.

 Source: Author

Step 8: Copy the invoke URL that appeared on your screen because we’ll need this later, so pull up a notepad or wherever you want to keep this. It will act as our API gateway URL.

 Source: Author

Step 9: Let’s go and validate this API. Come into resources in the sidebar and select POST.  Click on the Test option. This will let us send the test data we want and show the corresponding response.

 Source: Author

Step 10: We used the same format to test the lambda function. Pass the required password properties in JSON format and click the test button. We can see that our API worked successfully, and we received the response, which contains our password and success status code.

 image.png

Storing the Data in a Database

We don’t actually have to store the results anywhere we could return them to the user, but most real-world apps have databases. So, we have to set up a database, and also we need to handle permissions between the different parts of the application specifically, we need to give our lambda function permission to write to the database. Starting with the database, we’re going to use DynamoDB, a key value or NoSQL database it’s generally going to be more lightweight than something like a relational database, where you have to set up your schema and relationships ahead of time.

Step 1:  Go to the console, search for DynamoDB, and click Create a Table.

 Source: Author
 image.png

Step 2: Give a name for the table; for the partition key, let’s give the name as ‘ID’. You can leave everything else the same and create a table.

 Source: Author

Step 3: Now we need to save the Amazon resource name or the ARN; for this, click the table name, and under general information, in additional
info, you can find the ARN. Save this ARN. We will come back and get that later.

 Source: Author

Step 4: To give write permission to the lambda function, go to the lambda service and go to the configuration tab then, you need to click on the role name in the execution role. This should open up in a new tab.

 Source: Author

Step 5: We basically need to add some permissions to what this role already has. To do that, click on add permissions and create inline policy.

 Source: Author

Step 6: Working with the JSON code is easier, so click on the JSON tab there. Place this code in that tab.

{
"Version": "2012-10-17",
"Statement": [
    {
        "Sid": "VisualEditor0",
        "Effect": "Allow",
        "Action": [
            "dynamodb:PutItem",
            "dynamodb:DeleteItem",
            "dynamodb:GetItem",
            "dynamodb:Scan",
            "dynamodb:Query",
            "dynamodb:UpdateItem"
        ],
        "Resource": "YOUR-TABLE-ARN"
    }
    ]
}

It allows all these specified actions in JSON so that the lambda function will have permission to do all of these things on our DynamoDB table. Still, very importantly, you need to update the table ARN that you copied and click on Review Policy.

 Source: Author

Step 7: Now, name this policy and, finally, create a policy.

 Source: Author

Step 8: We need to update the lambda function Python code to interact with the database. Our previous code doesn’t have this functionality.

import json
import random
import string
# import the AWS SDK (for Python the package name is boto3)
import boto3
# create a DynamoDB object using the AWS SDK
dynamodb = boto3.resource('dynamodb')
# use the DynamoDB object to select our table
table = dynamodb.Table('PasswordDatabase')
def lambda_handler(event, context):
    # Extract input parameters from the event object
    name = event['name']
    length = int(event['length'])
    req_capital_letters = int(event['reqCapitalLetters'])
    req_small_letters = int(event['reqSmallLetters'])
    req_numbers = int(event['reqNumbers'])
    req_special_chars =int(event['reqSpecialChars'])
    # Generate the password
    password_chars = []
    allowed="" #allowed characters
    # Include one character from each selected character set
    if req_capital_letters:
        password_chars.append(random.choice(string.ascii_uppercase ))
        allowed=allowed+string.ascii_uppercase
    if req_small_letters:
        password_chars.append(random.choice(string.ascii_lowercase))
        allowed=allowed+string.ascii_lowercase
    if req_numbers:
        password_chars.append(random.choice(string.digits))
        allowed=allowed+string.digits
    if req_special_chars:
        password_chars.append(random.choice(string.punctuation))
        allowed=allowed+string.punctuation
    # Calculate the remaining length for random characters
    remaining_length = length - len(password_chars)
    # Generate random characters for the remaining length
    password_chars.extend(random.choice(allowed) for _ in range(remaining_length))
    # Shuffle the characters to remove order bias
    random.shuffle(password_chars)
    # Concatenate the characters to form the password
    password = ''.join(password_chars)
    
    # write result to the DynamoDB table using the object we instantiated 
    response = table.put_item(
        Item={
            'ID': name,
            'Password':password
            })

    # Return the password in a JSON response
    return {
        'statusCode': 200,
        'body': json.dumps('Your password for '+name+' is: ' + password)
    }

What’s new here in this code is we have imported a module for the AWS SDK(Software development kit) called boto3, and then we’re getting our
boto3 resource object for DynamoDB. Next, we use this object to connect our DynamoDB table by passing the table name; the rest is the same
as what we had before. Still finally, the code inserts the name of the password and the generated password into the table using the table.put_item() function.

 Source: Author

Step 9: Make sure you save this code with a CTRL+S and, very importantly, make sure you deploy this code, and then let’s test this code by hitting the
test button. We can see that our code is working fine, and it is giving the correct result.

 Source: Author

Step 10: Let’s check whether these results are updated in DynamoDB Table by going into explore table items this will show you what’s been stored.

 Source: Author

We can see that we have a new result now in the table, this result just came through from us running the test for the lambda function.

 Source: Author

Connecting the Frontend to the Backend

As of now, we’re able to write things to the DynamoDB table, and we’ve got the proper permissions on the lambda function, but you might have noticed
that we’re missing a connection between Amplify and the API gateway. Currently, from our index.html page, there is no way to trigger our lambda function. So, let’s
work on this final piece.

We need to update the index.html page to call the API gateway. Here is the link to the final index.html code.

Code explanation: Initially, in the style section, we did a little bit of styling to get a better look at h1 tags, inputs, and forms on our webpage. You can modify and update the CSS based on your preferences. We have an h1 tag, “Password Generator,” in the body section. This will be our webpage heading. Next, we have a form where the user will input the name and the properties of the password using checkboxes, and we have a button to submit the form, which invokes the “call API” function, and it is defined in the script tag. We are passing the name and length of the password as parameters to this function. In this function, we are initializing the values of properties as 0 or 1 based on user input in the form.

We are creating a JSON object with these values and calling the endpoint by passing this object in the request body. Finally, we are raising an alert in the browser that pops up with the response from the API gateway.

Now we have to Redeploy our index.html page using Amplify. Make a zip file out of this file again. Open Amplify and drag & drop the zip file. It should be deployed in a few seconds, and we will get the link to hosted application.

 Source: Author

Just open the link. We can see that our application deployed successfully.

 Source: Author
 Source: Author
 Source: Author

Here we go; the result is successfully updated in our DynamoDB database.

Delete your Resources

If you’ve followed along, let’s delete everything we spun up in this article. Everything should be in the free tier, just in case you don’t want any surprise bills at the end of the month.

Step 1: Go to your amplify resource, go to actions on the top right, and click delete app. You’ll need to confirm the operation before the deletion.

 Source: Author

Step 2: Next, come over to DynamoDB and click on tables. Select the table and click delete. This also has confirmation required before deletion.

 Source: Author

Step 3: Next, you can go and delete your lambda function. Navigate to AWS Lambda, select functions in the sidebar, and then select the name of your
function. Then go to the actions dropdown and click on delete.

 Source: Author

Step 4:Lastly, API gateway. Select the API name, and under actions, click on delete.

 Source: Author

Conclusion

In this article, we have implemented an end-to-end web application using various AWS services. In this application, users can enter their password name and properties on a hosted and deployed webpage using AWS Amplify. When the user submits the password details, the script in the webpage calls the API gateway by passing the user data in the request body, which triggers the AWS lambda function, which does the computation and creates the password based on user input. The result gets written into the AWS DynamoDB database, and then we will get a message returned to us in the browser through the API gateway. We have seen the entire process of creating an API gateway, creating the Lambda function, configuring the database, and assigning user permissions for the Lambda function to write into the database. While the example is relatively simple, it covers essential components required for more complex real-world applications.

Key Takeaways

  1. AWS Amplify helps us to easily create and host web pages, making it ideal for front-end developers.
  2. AWS Lambda acts serverless backend service that invokes our code in response to triggers without the need to manage servers.
  3. API Gateway helps connect various services in a web application by providing an endpoint.
  4. DynamoDB can store the results generated by the Lambda function in JSON format using appropriate SDKs.
  5. Setting up permissions and configuring the necessary policies for AWS services is crucial to ensure the proper functioning of the application.

Frequently Asked Questions

Q1. Can you build a Web application on AWS?

A. Yes, you can build web applications on AWS. AWS provides various services and tools for web developers that enable developers to design, develop, and deploy web applications with ease.

Q2. How do I create a complete Web application in AWS?

A. Develop frontend and backend components using the tech stack of your choice and use AWS SDKs and APIs for integrating your application with AWS services. There are various database services available in AWS, like RDS and DynamoDB choose the appropriate service and configure and set up the database. Deploy the application using services like AWS Amplify or AWS Elastic Beanstalk.

Q3. How do I host a Web application on AWS?

A. AWS provides services like AWS Amplify and AWS Elastic Beanstalk for hosting the application. Choose the appropriate service and upload your application code into the service. Select an appropriate storage service based on your needs, like Amazon S3 for content storage, Amazon EBS or Amazon RDS for database content, and Amazon DynamoDB NoSQL database for your application data.

Q4. How much does running a web app on AWS cost?

A. The cost of running a web application in AWS is not fixed; it depends on several factors, like type of service, pricing model, and usage. For example, AWS API Gateway charges based on the number of requests and data transferred. These will vary based on your usage. Please Go through the AWS documentation to estimate the cost before using the service.

The media shown in this article is not owned by Analytics Vidhya and is used at the Author’s discretion. 

Frequently Asked Questions

Lorem ipsum dolor sit amet, consectetur adipiscing elit,

Responses From Readers

Related Courses