Building a Serverless App with AWS Lambda, S3, DynamoDB, and Python

In this project, we’ll be building a Serverless web applications using a combination of AWS services. leveraging AWS S3 for hosting, Lambda functions for data retrieval and storage, DynamoDB as a database, API Gateway for creating RESTful APIs, CloudFront for content delivery, and AWS WAF to secure protect us against SQL injection attacks. 

Table of Contents

What is serverless architecture?

Serverless architecture is a concept within cloud computing where the, provisioning, maintenance and scaling of the server that hosts the applications is handled by the cloud provider, in this case AWS. 

Applications are built using small, stateless functions that are triggered by events. These functions are executed in a managed environment and automatically scale based on demand. Serverless architecture offers benefits such as cost efficiency, scalability, reduced operational overhead, and rapid development.

What AWS Services are we using?

In todays project we’ll be using,

  • S3 bucket – 
  • AWS Lambda
  • Dynamo DB
  • AWS IP Gateway 
  • CloudFront
  • AWS Waf 
Setting up an AWS S3 bucket

Log into your AWS Account and navigate your way to the S3 Dashboard and Create a new S3 bucket. 

Provide a unique name for your bucket. It’s required to choose a name that is globally unique within the entire AWS S3 namespace. This ensures that there are no naming conflicts with existing buckets. Next, select the region where you want to host your web application.

Leave the rest of the settings as default and click create bucket at the bottom of the page. Once the bucket is created, you can upload your web application files. Click on your bucket and select the Upload option then Add files Or simply rag and drop them in.  You’ll find the application files here, Link to Repository
Create AWS WAF rules

Now load the WAF and Shield dashboard.

  • Click Create Web ACL.
  • Change the resource type to Amazon Cloud Front
  • Add a Name and a Cloud Watch Metric Name
  • Leave Body Size Limit as default.
  • Click Next
  • Click Add Rule and select Add managed rule groups.
  • Select AWS Managed Rule Groups, Scroll down and add a few rule sets. 
  • Scroll down to the bottom of the page and click add rules. 

Click on next until you reach the end, leaving the default settings as they are. Review your configurations and Create your web ACL. Y

Set up CloudFront CDN for S3 Bucket

Load the Cloud Front Dashboard and click Create Distribution. 

Under Origin Domain select the S3 bucket we created earlier and set the Origin Access to Origin Access Control Setting.  This ensures the S3 bucket is only accessible via the Cloud Front Distribution. 

 

Click Create New OAC.

In the popup leave the everything as default and click create. 

Under Default Cache Behavior change the following settings and leave the rest default. 

  • Allowed HTTP methods -> Get, Head, Options, Put, Post, Patch, Delete. 
  • Chache HTTP Methods -> Options. 
Under Web Application Firewall (WAF)
  • Tick Enable Security Protections and select use existing WAF Configurations
  • Select the Web ACL that we built in the last step. 
 
 

The last setting we need to change is the Default Root Object, set this to index.html. After you’ve set that click create Distribution. 

Once the new distribution is created click on Copy Policy. 

This policy will grant CloudFront access to our S3 bucket. To apply it, go back to the S3 service, select the bucket containing your website, and go to Permissions. In the Bucket Policy section, click on Edit, and paste the copied policy, and click on Save Changes.

Go back to your CloudFront distribution and grab the generated domain name and paste it into your browser, you should see this!


Configure DynamoDB and Lambda Functions

Next up, we need to create our DynamoDB Database, load up the Dynamo DB dashboard and click create table. 

Name the table EmployeeDB  for your table and specify the partition key value to employeeId, Leave all other settings at their defaults and create table. 

Configuring IAM roles and permissions for Lambda functions

Load up the IAM Services Dashboard and go to Roles on the left hand side and click create role. 

  • Set Trusted Entity Type to AWS Service 
  • Set Use Case to Lambda
  • Click Next

Under the permissions step search for AmazonDynamoDBFullAccess and tick it.  

It’s worth noting down here, that in a production environment you’d use the principle of least privilege here, giving the Lambda function only the minimum requirements it need to do it’s job.  

 

Click Next, enter a name for the Role and then click create. 

 

Create Lambda Functions
Next we’ll be creating 3 lambda functions to Get, Delete and Put data into our Dynamo DB. The code for the functions can be found here  Lambda Code. Navigate your way to the Lambda dashboard and click create function.
  • Choose Author From Scratch
  • Give the function the name DeleteEmployee
  • Set the Runtime to Python 3.12
  • Under Change Default Role, select,  Use an existing role, and from the dropdown list select the Role we built in the last section.
  • Create the Function.
  • Copy the code from the file delete.py and paste it into the Lambda_Function Tab. 
  • Click the Deploy button. 

Repeat those steps 2 more times for the GetEmployee function and InsertEmployee Function

  • GetEmployee = get.py – update line 5 to the region where your dynamo DB is hosted.
  • InsertEmployee = insert.py
Building and Deploying our API Gateway

Navigate your way to the API Gateway Dashboard.

  • Scroll down to the REST API section and click on Build.
  • Select New API, provide a name, change the API Endpoint type to Edge-Optimized and Then, click on Create API.
  • We now need to setup 3 different methods so we’re able to interact with our backend. 
  • lets start with GetEmployee 
  • Click Create Method, set method type to GET and select Lambda Function for the integration type. 
  • Under Lambda Function set the Region to the same Region you created the Lambda function in and select the GetEmployee function from the dropdown list. 
  • Click Create Method

Repeat that process two more times for the Insert Employee and Delete employee 

  • InsertEmployee method type needs to be POST
  • DeleteEmployee method type needs to be DELETE

With our 3 Methods now created we can now deploy the API. 

  • Click Deploy API 
  • Select *New Stage* and give it a name. 
  • Click Deploy. 

After successfully deploying our API in the API Gateway, we need to configure CORS (Cross-Origin Resource Sharing) to ensure proper communication between the API Gateway and CloudFront. CORS is necessary because these two services reside in different domains

On the Resources Tab click the button that states Enable CORS

Tick the following box’s, DELETE and GET, then click save. 

 

After Enabling CORS, you’ll need to redeploy the API to apply the changes. 

Click Deploy API and select the stage we created a few steps back and click deploy!

We now need to copy the invoke URL from the Stages section and paste it into our Scipt.js that’s hosted in our S3 bucket. 

 

Update the var API_ENDPOINT = “” with your URL of the API that we just created. 

Dont forget to upload the updated script.js to the S3 bucket we created way back at the start!

 

Testing our application.

Navigate to CloudFront, on your CloudFront Distribution copy the URL of your domain name and paste it into your browser. Enter some information in and click Create New Employee. 

You Should then see the Employee details appear below.  

You can check that it’s been written to the DB via this AWS cli command. 

aws dynamodb scan –table-name EmployeesDB –region us-east-1

Trouble Shooting a CORS issue.

Trying to input Employee data into the DynamoDB i received an error! Pressing F12 to look at the response, it states there a CORS error, “Cross-Origin Resource Sharing error: Missing Allow Origin Header”.  looking back at our CloudFront setup i notice there’s an option that we didn’t set up originally, “Response headers policy – optional”  checking out the options there’s a few for allowing CORS. Selecting the option “SimpleCORS – Allows all orginins for simple CORS requests” and then clearing the Cache for CloudFront fixed the CORS error. 

Conclusion

That’s a wrap, we’ve utilised 6 different AWS Serverless function to build a serverless web app! using S3 for hosting, Cloud Front for content delivery, AWS WAF to add a layer of security and API Gateway for RESTful API integration and a back end of AWS Lambda, DynamoDB for storage.   In the next blog i’ll be utilizing AWS Cognito to add authentication to the webpage ->