Cloud Resume Challenge Part 2: Tracking Your Portfolio Traffic

Cloud Resume Challenge Part 2: Tracking Your Portfolio Traffic

Hello cloud fans! In this next step of our resume challenge, we're going to keep track of how many people visit our blog using AWS. We will use a Lambda function to save these numbers into a DynamoDB database and connect everything with an API Gateway endpoint. If you missed the earlier part, make sure to read it first. Let's get started!

Step 1: Creating the DynamoDB Table

💡
Amazon DynamoDB is a managed NoSQL service offering fast performance and scalability. It supports key-value and document data structures, handles administrative tasks, and is ideal for internet-scale applications with built-in security and in-memory caching features.

So, we will create a table to store the visitor count. Just head to your console, type DynamoDB in the search bar, and follow these steps.

Start by choosing a name for your table. Be careful with this name because it will be used in the Lambda code in the next step.

And do the same for the partition key. You can leave the Sort key empty.

Choose Customize settings and select On-demand pricing (to stay within the free tier).

You can leave the rest as default and create the table.

Step 2: Create Lambda Function

We will create a backend Lambda function using Python. Head to your console, type "Lambda" in the search bar, and create your Lambda function with Python 3.12 (or another language). For a step-by-step tutorial, visit this link.

Copy and paste the provided code into the designated area, then be sure to click 'Deploy' to activate it. Remember to replace TableName and partition_key with the specific names you have selected earlier.

import json
import boto3
from botocore.exceptions import ClientError

# Initialize the DynamoDB client
client = boto3.client('dynamodb')

# Access environment variables
TableName = "Visitors"
partition_key = "stat"

def lambda_handler(event, context):
    try:
        current_view_response = client.get_item(
            TableName=TableName,
            Key={partition_key: {'S': 'view-count'}}
        )
        if 'Item' in current_view_response and 'Quantity' in current_view_response['Item']:
            current_view_count = int(current_view_response['Item']['Quantity']['N'])
        else:
            current_view_count = 0  # Initialize if not present
    except ClientError as error:
        print(error)
        raise

    # If the Quantity was not set, increment the page view count
    if current_view_count == 0:
        newCount = current_view_count + 1
        try:
            client.update_item(
                TableName=TableName,
                Key={'stat': {'S': 'view-count'}},
                UpdateExpression='SET Quantity = :val',
                ExpressionAttributeValues={':val': {'N': str(newCount)}},
                ReturnValues='UPDATED_NEW'
            )
        except ClientError as error:
            print(error)
            raise
    else:
        # If the Quantity is set, use the existing count
        newCount = current_view_count

    return {
        'statusCode': 200,
        'headers': {
            'Content-Type': 'application/json',
            'Access-Control-Allow-Headers': 'Content-Type',
            'Access-Control-Allow-Origin': '*',
            'Access-Control-Allow-Methods': 'OPTIONS,POST,GET',
        },
        'body': json.dumps({'count': newCount})
    }

Attempting to test the code at this stage will result in an error message.

{
  "errorMessage": "An error occurred (AccessDeniedException) when calling the GetItem operation: User: arn:aws:sts::<account_number>:assumed-role/visitor-role-xxxxxx/visitor is not authorized to perform: dynamodb:GetItem on resource: arn:aws:dynamodb:us-east-1:<account_number>:table/Visitors because no identity-based policy allows the dynamodb:GetItem action",
  "errorType": "ClientError",
  "requestId": "7c819f77-21c6-45fb-9248-0a0dd5f0a0ca",
  "stackTrace": [
    "  File \"/var/task/lambda_function.py\", line 13, in lambda_handler\n    current_view_response = client.get_item(\n",
    "  File \"/var/lang/lib/python3.12/site-packages/botocore/client.py\", line 553, in _api_call\n    return self._make_api_call(operation_name, kwargs)\n",
    "  File \"/var/lang/lib/python3.12/site-packages/botocore/client.py\", line 1009, in _make_api_call\n    raise error_class(parsed_response, operation_name)\n"
  ]
}

This is an indicator that your Lambda function lacks the necessary permissions to interact with the earlier created DynamoDB table. Let's address this by updating the function's permissions.

Let's resolve this by adding an inline policy to grant Lambda the permissions it requires.

Next, paste the policy into the appropriate section, and remember to substitute the account_id, region and TableName placeholders with your actual account details for a seamless setup.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Statement1",
            "Effect": "Allow",
            "Action": [
              "dynamodb:GetItem",
              "dynamodb:UpdateItem",
              "dynamodb:PutItem",
              "dynamodb:Scan",
              "dynamodb:DeleteItem"
            ],
            "Resource": [
                "arn:aws:dynamodb:<region>:<account_id>:table/<TableName>"
            ]
        }
    ]
}

Once you've entered the policy details, simply assign a name to your policy and click the 'Create policy' button to finalize the process.

Now that you've set the permissions, it's time to test it out. Cross your fingers, press that button, and with a little bit of tech magic, it should work like a charm!

Step 3: Add an API Gateway trigger

💡
Amazon API Gateway is a fully managed service allowing developers to create, publish, maintain, monitor, and secure APIs at any scale. It acts as a front door for applications, facilitating communication between client interfaces and backend services.

Adding a trigger to your Lambda function is straightforward—just a simple button click away. Navigate to your Lambda function's configuration and effortlessly add the trigger.

Choose API Gateway

Next, you'll need to choose between REST API and HTTP API. To make an informed decision, I suggest perusing the accompanying documentation.

Leave the remaining settings at their default values and then click 'Add' to proceed.

To test if you've done it well, click on the link an refrech the page and see if the count increases.

Conclusion

By following these steps, you've set up a system to track and store your portfolio traffic using AWS services. This enhances your resume and provides insights into your website's performance. Keep experimenting and expanding your cloud skills!

  1. Created a DynamoDB table to store visitor counts.

  2. Developed a backend Lambda function using Python to interact with the DynamoDB table.

  3. Configured necessary IAM permissions for the Lambda function.

  4. Added an API Gateway trigger to the Lambda function.

  5. Tested the setup to ensure it tracks and stores portfolio traffic successfully.

I have created a GitHub repository to automate the process using Terraform. Enjoy your traffic and stay tuned for the next part, where we will link our front-end code with the endpoint we created today.