A Journey in Learning

Creating the Website Counter with Python, Javascript, and AWS

This is going to be a long post. I have successfully completed the Cloud Challange mostly. I have completed all the difficult hurdles and now will be continuing to find new problems to solve.

Today I was able to finally get a working website counter to appear on my landing page that is powered by AWS services. I used a REST API to invoke a lambda function with two actions. One is to update my Visitor Counter value is DynamoDB and the other is to query the number of visits total. This response is then routed through a REST API and integrated into a mapping template that spits out simple JSON. the Python needed is seen below

def Website_CounterUpdater(event, context):
  
  table.update_item(
    Key={
      'URL': "Alkisnar.IO",
      'Page': "ResumePage"
    },
    UpdateExpression='set VisitCount = VisitCount + :increment',
        ExpressionAttributeValues={
            ':increment': 1
        }    
    )

  items = table.get_item(
    Key={
      'URL': "Alkisnar.IO",
      'Page': "ResumePage"
    })
    
  return items

The JSON response is seen as:

{
  "Item": {
    "URL": "Alkisnar.IO",
    "VisitCount": 788,
    "Page": "ResumePage"
  },
  "ResponseMetadata": {
    "RequestId": "P4EALP08MOBPV9AK7D252I88E3VV4KQNSO5AEMVJF66Q9ASUAAJG",
    "HTTPStatusCode": 200,
    "HTTPHeaders": {
      "server": "Server",
      "date": "Sat, 21 Nov 2020 09:21:10 GMT",
      "content-type": "application/x-amz-json-1.0",
      "content-length": "87",
      "connection": "keep-alive",
      "x-amzn-requestid": "P4EALP08MOBPV9AK7D252I88E3VV4KQNSO5AEMVJF66Q9ASUAAJG",
      "x-amz-crc32": "1033407308"
    },
    "RetryAttempts": 0
  }
}

The reason I added Stanley Hudson as a gif for this post is because I spent three hours trying to sparse out the data needed from my JSON response. Again, going down the wrong rabbit hole out of exhaustion and frustration but learning quite a bit about JavaScript in the process.

My original approach was to try parsing out the VisitCount value but I soon learned that I cannot parse out one object that is part of an array without lots of extra work that wasn’t really needed. I figured out intimate details about the following piece of code

<script>
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
  if (this.readyState == 4 && this.status == 200) {
    var myObj = JSON.parse(this.responseText);
    document.getElementById("prod").innerHTML = myObj.VisitCount;
  }
};
xmlhttp.open("GET", 'https://pxby95zsx5.execute-api.us-east-1.amazonaws.com/prod', true);
xmlhttp.send();
</script>

This code kept receiving and Undefined error until I started to experiment and realized that this JSON was an array of two objects and that another approach using Jquery and console.log would be much easier. I was able to use this approach and get a working counter. see this code below

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script>
      var settings = {
        "async": true,
        "crossDomain": true,
        "url": "https://pxby95zsx5.execute-api.us-east-1.amazonaws.com/prod",
        "method": "GET"
      }
      $.ajax(settings).done(function (response) {
        console.log(response);

        var content = response.Item.VisitCount;
        $("#Visitors").append(content);

      });
   </script>

I would like to thank https://idratherbewriting.com/ for a tutorial.

What I learned

  1. REST API’s will need CORS enabled if you plan on doing any kind of testing on your local machine using a different Domain to invoke the REST API, also this applies if your using a website that has Javascript tutorials that run in browser
  2. Its best to have external API’s that run on lambda only be able to request information for the specific table you need to query, and also only be able to update that table. Principle of least privilege’s
  3. REST API’s are the best to map out a specific response to be returned back to your web-browser, I used a get method and implemented a lean Mapping template to only return my function read query and some mandatory Metadataresponse from boto3 python.
  4. Parsing doesn’t work easily on an array, unless you want to spend countless hours trying to figure it out, its better to use a Console.log to pull out the data you need. Even then you will need to specify which object and which value accordingly CatagoryofObjects.Value so that you can traverse JSON’s hierarchy.