Cloud Resume Challenge - Visitor Counter
Cloud Resume Challenge - JavaScript / Database / API / Lambda
Date: February 26, 2025 Status: Done
Overview:
- DynamoDB:
- Create a table with a primary key/value (e.g.,
VCID
) and an attribute to store the visitor count.
- Create a table with a primary key/value (e.g.,
- Lambda function (Python):
- Create lambda function with default execution role
- Edit default role to enable access to DynamoDB
- Write Python to:
- Initialize DynamoDB connection using
boto3
. - Fetch the visitor count from DynamoDB.
- Increment the count.
- Save the updated count back to DynamoDB.
- Return the updated count.
- Initialize DynamoDB connection using
- Add a public endpoint trigger to the lambda function using Amazon API Gateway
- Frontend (JavaScript):
- Call the API Gateway using
fetch()
. - Display the returned visitor count.
- Call the API Gateway using
1. DynamoDB Table Setup ✅
Choosing the Right DynamoDB Partition Key - Amazon Web Services
Core components of Amazon DynamoDB - Amazon DynamoDB
- Go to the AWS DynamoDB console and create a new table (
VisitorCountTable
) withvisitor_count_id
as the partition key. - Set the initial count manually to 1.
- Create another attribute named
visitor_count
and set it to 0
2. Create Lambda Function and update default Lambda Role ✅
Permission Policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "UpdateDynamoDB",
"Effect": "Allow",
"Action": [
"dynamodb:UpdateItem",
"dynamodb:Scan"
],
"Resource": "arn:aws:dynamodb:us-east-1:123456789:table/VisitorCountTable"
}
]
}
3. Lambda Function Code (Python) ✅
Define Lambda function handler in Python - AWS Lambda
scan - Boto3 1.35.29 documentation
update_item - Boto3 1.35.26 documentation
message: “Internal server error” when try to access aws gateway api
import json
import boto3
client = boto3.client("dynamodb")
def lambda_handler(event, context):
return Get_Visitor_Count()
def Get_Visitor_Count():
##
response = client.scan(TableName="VisitorCountTable")
##
if "Items" in response:
# Save the response (JSON)
count = response["Items"][0]["visitor_count"]["N"]
count = int(count)
else:
count = 0
count += 1
request = client.update_item(
ExpressionAttributeNames={
"#VC": "visitor_count",
},
ExpressionAttributeValues={
":count": {
# N is attribute of type number
"N": str(count),
},
},
Key={
"visitor_count_id": {
"N": "1",
},
},
ReturnValues="ALL_NEW",
TableName="VisitorCountTable",
# An expression that defines one or more attributes to be updated, the action to be performed on them, and new values for them.
# SET - Adds one or more attributes and values to an item. If any of these attributes already exist, they are replaced by the new values.
UpdateExpression="SET #VC = :count",
)
return {
'statusCode': 200,
'headers': {'Content-Type': 'application/json'},
'body': json.dumps({'visitorcount': count})
}
4. Connect API Gateway & Lambda ✅
Invoking a Lambda function using an Amazon API Gateway endpoint - AWS Lambda
To add a public endpoint to your Lambda function
- Open the Functions page of the Lambda console.
- Choose a function.
- Under Function overview, choose Add trigger.
- Select API Gateway.
- Choose Create an API
- New API: For API type, choose HTTP API. For more information, see Choosing an API type.
- For Security, choose Open.
- Enable CORS -> Access-Control-Allow-Origin = *
- Choose Add then Save.
- Navigate to API Gateway > APIs > API you just created > Routes
- Edit Route to GET
5. Frontend (JavaScript) ✅
JavaScript Fetch API use cases for fetching data, JSON, XML, etc. - Learn JavaScript
Document: getElementById() method - Web APIs - MDN
Node: textContent property - Web APIs - MDN
Example HTML
<html lang="en">
<body>
Welcome, Visitor #<div id="VisitorCounter"></div>
</body>
</html>
Example JavaScript
<script>
fetch('https://aegjbsexha.execute-api.us-east-1.amazonaws.com/default/VisitorCounter')
.then(response => response.json())
.then(data => {
document.getElementById("VisitorCounter").textContent = data["visitorcount"];
})
</script>
Example CSS
.visitor-count {
position: absolute; /* Keeps the element fixed while scrolling */
top: 50px; /* Places the element 50px from the top */
left: 0; /* Aligns the element to the left */
width: 100%; /* Optional: makes the element span the full width of the page */
text-align: center; /* Optional: centers the text horizontally */
display: inline-block; /* Keeps this element as a block but inline with other elements */
z-index: 1000; /* Ensures the element stays on top of other content */
}
#VisitorCounter {
display: inline; /* Ensure the VisitorCounter div stays inline with the Welcome text */
}
6. Update href links with S3 URLs ✅
.social.twitter:before {
background: url("https://m0d-website.s3.amazonaws.com/images/twitter.png") center no-repeat;
}
.social.github:before {
background: url("https://m0d-website.s3.amazonaws.com/images/github.png") center no-repeat;
}
.social.linked-in:before {
background: url("https://m0d-website.s3.amazonaws.com/images/linkedin.png") center no-repeat;
}