Building a Serverless Web Application with AWS Lambda, API Gateway, DynamoDB, S3
In this article we are going to deploy web application on AWS in serverless way means we don’t have to manage servers at all, no scaling of servers nothing. In today’s world, most of the business need serverless architecture where they should mainly focus on building the businesses not managing the time in managing the servers or any kind of downtime.
Introduction to Serverless Architecture
Serverless means we just don’t have to manage the servers, allowing developers to write the code can deploy the code easily without managing the servers. Serverless is FaaS service means Functions As a Service by this serverless computing is highly available, efficient and makes it scalable.
Serverless architectures are based on EDA (Event Driven Architectures) that means it will triggered by some events like HTTP requests, file uploads or on schedule basis also.
As serverless is Pay As You go model that makes the cost-effective which means we are paying for the compute power that we use.
PreRequisites and AWS Services
AWS Account
IAM Role
AWS Lambda for writing functions or code where we will deploy
AWS API Gateway to create a RestFul API
NOSQL Database i.e DynamoDB
Deployment of Website on AWS
Before heading to AWS let me show you how the website look, and what we are going to achieve.
At the end of our blog, we had deployed this website on AWS and access this website with S3 Static Website Endpoint which means we are hosting this website on S3 (index.html) and when we fill the details it will show “Data Submitted Successfully“ and add the record into DynamoDB table.
GitHub Code : https://github.com/amitmaurya07/Serverless-AWS
IAM Role
Create the IAM role that will communicate with required services. Navigate to IAM, click on Create Role.
Now, select AWS service and choose Lambda under Usecase then give the required permissions for API Gateway, DynamoDB, S3 Bucket then click on Next and name the role
ServerlessWeb
and click on Create Role.AmazonAPIGatewayInvokeFullAccess
AmazonDynamoDBFullAccess
AmazonS3FullAccess
AWS Lambda
In AWS, we had EC2 instances which are virtual servers that has limited RAM and CPU where the EC2 instances are continuously running if they are stopped also so we are paying also this, and to scale EC2 instances we create Autoscaling Groups .
But in AWS Lambda they are virtual function which means we don’t need to manage the servers, don’t need to provision the servers and they run ON-DEMAND where scaling is automated.
It supports multiple programming languages like Node.js, Python, Golang, Java, C# and Ruby. On AWS Lambda it follows Pay AS You go model. In Free-tier AWS account it provides 1 million free requests.
Navigate to AWS Management Console and search Lambda
Click on Create Function name
Serverless-Web-App
, choose Runtime Python 3.13 then change the default execution role. Select Use an existing role which you had created earlierServerlessWeb
then click on Create on Create Function.Don’t worry we will see the API Gateway also when we create API Gateway. Now, paste the code and Deploy the changes.
import json import boto3 dynamodb = boto3.resource('dynamodb') table = dynamodb.Table('serverless-web-app') # Replace with your DynamoDB table name def lambda_handler(event, context): print(json.dumps(event)) if event['httpMethod'] == 'OPTIONS': return { 'statusCode': 200, 'headers': { 'Access-Control-Allow-Origin': '*', # or your frontend domain 'Access-Control-Allow-Headers': 'Content-Type,X-Amz-Date,Authorization,X-Api-Key', 'Access-Control-Allow-Methods': 'POST,OPTIONS' # Allow POST and OPTIONS methods }, 'body': json.dumps('CORS Preflight Request handled successfully') } # POST Request Handling if event['httpMethod'] == 'POST': # Check if the body is present in the event if 'body' not in event: return { 'statusCode': 400, 'headers': { 'Access-Control-Allow-Origin': '*' # Allow all domains or specify one }, 'body': json.dumps('Invalid request: No body in the request') } try: body = json.loads(event['body']) name = body.get('name') email = body.get('email') # Ensure both 'name' and 'email' are provided if not name or not email: return { 'statusCode': 400, 'headers': { 'Access-Control-Allow-Origin': '*' # Allow all domains or specify one }, 'body': json.dumps('Invalid input: Name and Email are required') } # Save to DynamoDB table.put_item( Item={ 'email': email, 'name': name } ) return { 'statusCode': 200, 'headers': { 'Access-Control-Allow-Origin': '*' # Allow all domains or specify one }, 'body': json.dumps('Data stored successfully!') } except json.JSONDecodeError: return { 'statusCode': 400, 'headers': { 'Access-Control-Allow-Origin': '*' }, 'body': json.dumps('Invalid JSON format') } except Exception as e: return { 'statusCode': 500, 'headers': { 'Access-Control-Allow-Origin': '*' }, 'body': json.dumps(f"Internal Server Error: {str(e)}") }
In this code we have to replace our DynamoDB table name in 5th line. After deploying the changes go to API Gateway
API Gateway
API Gateway are serverless API’s that provide Restful API’s to the clients and after integrating with Lambda it proxy the requests to our Lambda functions.
It has 3 endpoint types:
Regional - It is for the same region.
Private - It can be accessed from private VPC with the help of VPC Endpoint.
Edge-Optimized (default) - To improve latency requests are routed through Cloudfront edge locations.
Now, navigate to AWS Management Console and search for API Gateway.
Click on Create API and choose the API type REST API.
Click on Build and name it
Web-App
, select Regional Endpoint Type then click on Create API.Now, create the method POST and OPTIONS. Click on
Web-App
then click on Create Method.Select Method Type POST, Integration type Lambda enable the Lambda Proxy Integration by which entire HTTP request will be forwarded to Lambda function. Choose the Lambda function ARN which we created earlier
Serverless-Web-App
then click on Create Method.Now, we have to create another method type OPTIONS that will handle CORS error and preflight requests. Select MOCK Integration Type and choose the same Lambda function
Serverless-Web-App
.Now, click on OPTIONS method and add method Method Response under 200 Status Code. Click on Create Response under Header Name add these headers.
Access-Control-Allow-Headers
Access-Control-Allow-Methods
Access-Control-Allow-Origin
Then click on Save.
Go to Integration Response under OPTIONS method add the value to the Response headers.
Access-Control-Allow-Headers
'Content-Type, Authorization'
Access-Control-Allow-Methods
'POST, GET, OPTIONS'
Access-Control-Allow-Origin
'*'
Click on Save.
Click on POST method and add same Method Response headers.
Now, click on deploy the API where you need to create New Stage to save the changes.
Scroll down, you will get the Invoke URL and add this URL in index.html file.
DynamoDB
AWS offers DynamoDB which is NoSQL database which is highly scalable, and fully managed serverless database solution that can handle millions of requests per second, offers low latency which stores and retrieve structured data.
Navigate to AWS Management Console and search DynamoDB
Click on Create Table name
web-app
, write partition key email as we are only storing email that wants to be unique ID then click on Create Table.
After this, copy the table name web-app
and paste in Lambda function where we had defined.
After doing changes, paste the same to Lambda function and deploy the changes in Lambda.
Host Static Website on S3
Now, we are going to host our static website index.html on S3 bucket which is serverless.
If you want to host static website on S3 with Terraform Modules you can refer to this article.
Deploying Your Website on AWS S3 with Terraform
Navigate to AWS Management Console and search S3. Remember we will be creating the bucket in Mumbai (ap-south-1)
Create the bucket with your preferred name as name has to be unique across Global. While creating bucket uncheck the “Block all Public Access” then click on Create bucket and upload index.html file in the bucket.
Scroll down in Properties section of S3 bucket and enable the Static Website Hosting type index document index.html
You will receive endpoint to open the website but it will give you error because you hadn’t added the Permissions. Navigate to Permissions tab in S3 bucket and add bucket policy.
{ "Version": "2012-10-17", "Statement": [ { "Sid": "PublicReadGetObject", "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::serverlesswebapp07/*" } ] }
In Resource change the bucket name to your bucket name.
Now, when you refresh the page you will access the website. So, we hosted the static website successfully on S3 bucket.
Now, let’s check our API, Lambda and DynamoDB is perfectly working or not.
As we can see data is submitted successfully our API is getting 200 status code. Let’s check also our DynamoDB table recorded the email or not.
As we can see our email and Name is there in database. We can check also with PostMan, for this select the POST method response and paste the API Gateway URL and in raw select JSON body.
Conclusion
In this article, we explored the deployment of our website on AWS using a serverless approach. In upcoming posts, we will delve into the creation of various AWS services and their automation with Terraform. Stay tuned for the next blog!
GitHub Code : https://github.com/amitmaurya07/Serverless-AWS
Twitter : x.com/amitmau07
LinkedIn : linkedin.com/in/amit-maurya07
If you have any queries you can drop the message on LinkedIn and Twitter.
Subscribe to my newsletter
Read articles from Amit Maurya directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Amit Maurya
Amit Maurya
DevOps Enthusiast, Learning Linux