I am trying to setup a view counter for the AWS #CloudResumeChallenge. I am following the instructions on these two youtube videos:
I am also using both of these gentlemen's GitHub repos as references:
I have followed the video's instructions, step-by-step; however, when I load my cloud resume at https://justinhenson.cloud/, the visitor counter is showing "[object Object]" and upon inspecting the element, the original line in my index.html file changes from this:
<div id="visitors" class="visitors"> You are visitor number<span id="visits"></span><span id="loader" class="loader"></span></div>
To this:
<div id="visitors" class="visitors"> You are visitor number<span id="visits">[object Object]</span><span id="loader" class="loader" style="display: none;"></span></div><span id="visits">[object Object]</span><span id="loader" class="loader" style="display: none;"></span></div>
Also, as you can see in my scripts.js file below, I have pointed the pathway to the AWS API Gateway to trigger the lambda handler:
"use strict";
$(document).ready(() => {
$.post('https://pl8h7bxm3j.execute-api.us-east-1.amazonaws.com/Prod/visit/')
.done(visitor_counter => {
$('#loader').hide();
$('#visits').text(visitor_counter);
})
.fail(e => {
console.log('Error');
console.log(e);
});
});
I have tested my API Gateway with the Postman app and it returns the count without error:
I followed both of the instructions in the videos by enabling the CORS policy in my lambda handler in the "app.py" file to be wide open to reduce complexity:
import json
import boto3
dynamodb = boto3.resource('dynamodb', region_name='us-east-1')
table = dynamodb.Table('resume-website-app-tbl')
def lambda_handler(event, context):
response = table.get_item(
Key = {
'ID':'visits'
}
)
visit_count = response['Item']['counter']
visit_count = str(int(visit_count) + 1)
response = table.put_item(
Item = {
'ID':'visits',
'counter': visit_count
}
)
return {
'statusCode': 200,
'headers': {
'Access-Control-Allow-Headers': '*',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': '*'
},
'body': json.dumps({'visit_count': visit_count})
}
Below is my template.yaml file that I built with SAM that contains the configuration for my CloudFront Distribution under "MyDistribution" and the configuration for MyLambdaFunction:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
cloud-resume
Sample SAM Template for cloud-resume
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 3
Resources:
ResumeWebsite:
Type: AWS::S3::Bucket
Properties:
AccessControl: PublicRead
WebsiteConfiguration:
IndexDocument: index.html
BucketName: justinhenson-cloud-resume-website
MyRoute53Record:
Type: "AWS::Route53::RecordSetGroup"
Properties:
HostedZoneId: Z01881203GO4SRLRJE2CO
RecordSets:
- Name: justinhenson.cloud
Type: A
AliasTarget:
HostedZoneId: Z2FDTNDATAQYW2
DNSName: !GetAtt MyDistribution.DomainName
MyCertificate:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: justinhenson.cloud
ValidationMethod: DNS
MyDistribution:
Type: "AWS::CloudFront::Distribution"
Properties:
DistributionConfig:
ViewerCertificate:
AcmCertificateArn: !Ref MyCertificate
SslSupportMethod: sni-only
Aliases:
- justinhenson.cloud
DefaultCacheBehavior:
ViewerProtocolPolicy: redirect-to-https
TargetOriginId: justinhenson-cloud-resume-website.s3.us-east-1.amazonaws.com
DefaultTTL: 0
MinTTL: 0
MaxTTL: 0
ForwardedValues:
QueryString: false
Origins:
- DomainName: justinhenson-cloud-resume-website.s3.us-east-1.amazonaws.com
Id: justinhenson-cloud-resume-website.s3.us-east-1.amazonaws.com
CustomOriginConfig:
OriginProtocolPolicy: http-only
Enabled: "true"
DefaultRootObject: index.html
BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
PolicyDocument:
Id: MyPolicy
Version: 2012-10-17
Statement:
- Sid: PublicReadForGetBucketObjects
Effect: Allow
Principal: "*"
Action: "s3:GetObject"
Resource: !Join
- ""
- - "arn:aws:s3:::"
- !Ref ResumeWebsite
- /*
Bucket: !Ref ResumeWebsite
MyDynamoDBTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: resume-website-app-tbl
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: "ID"
AttributeType: "S"
KeySchema:
- AttributeName: "ID"
KeyType: "HASH"
MyLambdaFunction:
Type: AWS::Serverless::Function
Properties:
Policies:
- DynamoDBCrudPolicy:
TableName: resume-website-app-tbl
CodeUri: hello_world/
Handler: app.lambda_handler
Runtime: python3.9
Architectures:
- x86_64
Events:
Visits:
Type: Api
Properties:
Path: /visit
Method: post
HelloWorldFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: hello_world/
Handler: app.lambda_handler
Runtime: python3.9
Architectures:
- x86_64
Events:
HelloWorld:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /hello
Method: get
Outputs:
# ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
# Find out more about other implicit resources you can reference within SAM
# https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
HelloWorldApi:
Description: "API Gateway endpoint URL for Prod stage for Hello World function"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
HelloWorldFunction:
Description: "Hello World Lambda Function ARN"
Value: !GetAtt HelloWorldFunction.Arn
HelloWorldFunctionIamRole:
Description: "Implicit IAM Role created for Hello World function"
Value: !GetAtt HelloWorldFunctionRole.Arn
I sincerely appreciate any help anyone can offer in shedding some light on this issue. Thanks.
You are trying to put all HTTP response object to html, so you get [object Object]
$(document).ready(() => {
$.post('https://pl8h7bxm3j.execute-api.us-east-1.amazonaws.com/Prod/visit/')
.done(res => {
$('#loader').hide();
$('#visits').text(res.visit_count);
})
.fail(e => {
console.log('Error');
console.log(e);
});
});