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 has a endless spinning circle and I get the following error when I inspect the visitor counter element:
Access to XMLHttpRequest at 'https://pl8h7bxm3j.execute-api.us-east-1.amazonaws.com/' from origin 'https://justinhenson.cloud' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Failed to load resource: net::ERR_FAILED
pl8h7bxm3j.execute-api.us-east-1.amazonaws.com/:1
Below is my template.yaml file that I built with SAM that contains the configuration for my CloudFront Distribution under "MyDistribution":
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
Additionally, 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 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})
}
Also, as you can see in my scripts.js file below, I have pointed the pathway to the API Gateway to trigger the lambda handler:
"use strict";
$(document).ready(() => {
$.post('https://pl8h7bxm3j.execute-api.us-east-1.amazonaws.com')
.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:
And a copy of my index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<title>Justin Henson</title>
<link rel="icon" type="image/x-icon" href="img/favicon.ico" />
<meta name="robots" content="noindex,nofollow" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/css/bootstrap.min.css" />
<link rel="stylesheet" href="css/styles.css" />
<link rel="preconnect" href="https://fonts.gstatic.com" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700;900&display=swap" />
</head>
<body>
<div class="container my-3 my-md-5">
<div class="row">
<header class="col-12 col-md-4 col-lg-4">
<aside class="sidebar text-center px-2 px-md-3 px-lg-5 py-4 py-md-5">
<div class="sticky-wrap">
<div id="user-info" class="user-info">
<div class="about"><a href="img/profile.jpeg" alt="Jusitn Henson"><img src="img/profile.jpeg" alt="Jusitn Henson" class="profile-pic img-fluid rounded-circle" /></a>
<h1 class="name mt-3 mb-1">Justin Henson</h1>
<p class="job-name mb-0">AWSx2 / Cloud Engineer / Developer</p>
<p></p>
<p class="job-name mb-0"><a href="mailto:justin.henson@proton.me">Email Me / </a><a href="https://www.linkedin.com/in/justin-henson/">LinkedIn Profile</a></p>
<p class="job-name mb-0"> <a href="https://justinhenson.cloud/Justin-Henson-Resume.docx" target="_blank">Download My Resume</a></p>
<p class="job-name mb-0"><a href="tel:+15124877189">(512)-487-7189</a></p>
<p></p>
<div id="user-info" class="user-info">
<div class="social-icons">
<ul class="list-unstyled mb-0">
<li>
<a href="https://github.com/justin-scripts" class="test">
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<title>GitHub icon</title>
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" />
</svg>
</a>
</li>
<li>
<a href="https://www.linkedin.com/in/justin-henson/">
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"></path>
</svg>
</a>
</li>
</ul>
</div>
<div id="visitors" class="visitors"> You are visitor number<span id="visits"></span><span id="loader" class="loader"></span></div>
</div>
</div>
</div>
</aside>
</header>
<main class="col-12 col-md-8 col-lg-8">
<div class="content ml-0 ml-md-2 mr-0">
<section id="about" class="section mt-3 mt-md-0 p-3">
<h3 class="mb-3 text-uppercase">About</h3>
<p>
I enjoy mastering new technology and sharing that knowledge with others, while creating value for businesses and the cloud community.
</p>
<p>
This is a condensed resume for <a href="https://cloudresumechallenge.dev/">The Cloud Resume Challenge</a>.
To view my full resume, please visit my <a href="https://www.linkedin.com/in/justin-henson/">LinkedIn Profile</a>.
</p>
</section>
<section id="experience" class="section mt-3 mt-md-5 p-3">
<h3 class="mb-3 text-uppercase">Experience</h3>
<div class="row mt-4 mb-2">
<div class="col-6">
<span class="tiny-super font-weight-bold">VarsityTutors.com</span>
<span class="tiny-super d-block title">AWS / Python Tutor</span>
</div>
<div class="col-6 text-right"> <span class="tiny-super date">Jan, 2022 - Current</span> </div>
</div>
<div class="row mt-4 mb-2">
<div class="col-6">
<span class="tiny-super font-weight-bold">Powur, PBC</span>
<span class="tiny-super d-block title">Independent Solar Consultant</span>
</div>
<div class="col-6 text-right"> <span class="tiny-super date">Mar, 2021 - Dec, 2021</span> </div>
</div>
<div class="row mt-4 mb-2">
<div class="col-6">
<span class="tiny-super font-weight-bold">Eco-Héroes De La Tierra</span>
<span class="tiny-super d-block title">Founder & CEO</span>
</div>
<div class="col-6 text-right"> <span class="tiny-super date">Jun, 2014 - Dec, 2021</span> </div>
</div>
<div class="row mt-4 mb-2">
<div class="col-6">
<span class="tiny-super font-weight-bold">The Amazon Rescue Center</span>
<span class="tiny-super d-block title">Web Designer and Administrator</span>
</div>
<div class="col-6 text-right"> <span class="tiny-super date">Feb, 2018 - Jun, 2019</span> </div>
</div>
<div class="row mt-4 mb-2">
<div class="col-6">
<span class="tiny-super font-weight-bold">Bottle Buildings & Bamboo Bicycles in Guatemala</span>
<span class="tiny-super d-block title">Co-Founder & CEO</span>
</div>
<div class="col-6 text-right"> <span class="tiny-super date">Nov, 2012 - Jun, 2014</span> </div>
</div>
<div class="row mt-4 mb-2">
<div class="col-6">
<span class="tiny-super font-weight-bold">Tainan City International English Village</span>
<span class="tiny-super d-block title">English Second Language Teacher</span>
</div>
<div class="col-6 text-right"> <span class="tiny-super date">Aug, 2010 - May, 2012</span> </div>
</div>
<div class="row mt-4 mb-2">
<div class="col-6">
<span class="tiny-super font-weight-bold">IBM</span>
<span class="tiny-super d-block title">Network Software Engineer</span>
</div>
<div class="col-6 text-right"> <span class="tiny-super date">Jun, 2007 - Jul, 2009</span> </div>
</div>
<div class="row mt-4 mb-2">
<div class="col-6">
<span class="tiny-super font-weight-bold">Windstead PC</span>
<span class="tiny-super d-block title">IT Administrator</span>
</div>
<div class="col-6 text-right"> <span class="tiny-super date">Aug, 2005 - Jun, 2007</span> </div>
</div>
</section>
<section id="education" class="section mt-3 mt-md-5 p-3">
<h3 class="mb-2 text-uppercase">Education</h3>
<div class="row mt-4 mb-2">
<div class="col-6">
<span class="tiny-super d-block font-weight-bold">Springboard</span>
<span class="tiny-super">Program: 6 Month Data Science / ML Bootcamp</span>
</div>
<div class="col-6 text-right"> <span class="tiny-super">2023 - To Present</span> </div>
</div>
<div class="row mt-4 mb-2">
<div class="col-6">
<span class="tiny-super d-block font-weight-bold">freecodecamp.org</span>
<span class="tiny-super">Certificate: Responsive Web Design</span>
</div>
<div class="col-6 text-right"> <span class="tiny-super">2022</span> </div>
</div>
<div class="row mt-4 mb-2">
<div class="col-6">
<span class="tiny-super d-block font-weight-bold">National Pingtung University of Science and Technology</span>
<span class="tiny-super">Program: One Year Intensive Mandarin Study</span>
</div>
<div class="col-6 text-right"> <span class="tiny-super">2012</span> </div>
</div>
<div class="row mt-4 mb-2">
<div class="col-6">
<span class="tiny-super d-block font-weight-bold">University of North Texas</span>
<span class="tiny-super">Bachelor of Business Administration: Financial Analysis and Financial Management Services</span>
</div>
<div class="col-6 text-right"> <span class="tiny-super">2001</span> </div>
</div>
</section>
<section id="certifications" class="section mt-3 mt-md-5 p-3">
<h3 class="mb-3 text-uppercase">Certifications</h3>
<div>
<strong>AWS Certified Solutions Architect — Associate</strong>
<p>
<img src="img/aws_solutions_architect_assoc.png" class="aws-badge" alt="AWS Certified Solutions Architect Associate" />
<br />Issued November 09, 2022
<br /><a href="https://www.credly.com/badges/c73ccbf3-fc0e-4e08-a4ad-3f705553ae72/linked_in_profile">view credential</a>
</p>
</div>
<div>
<br /><br />
<strong>AWS Certified Cloud Practitioner</strong>
<p>
<img src="img/aws_cloud_practiotiner.png" class="aws-badge" alt="AWS Certified Cloud Practitioner" />
<br />Issued July 20, 2021
<br /><a href="https://www.credly.com/badges/c068a1c0-a90f-40ea-a6e0-d0e4cc5cac2b/linked_in_profile">view credential</a>
</p>
</div>
<div>
<br /><br />
<strong>CompTIA Network+ Certified</strong>
<p>
<img src="img/CompTIA_Network_Plus.png" class="aws-badge" alt="CompTIA Network+ Certified" />
<br />Issued February 27, 2006
<br /><a href="https://www.credly.com/badges/d5e353f4-672f-456c-ada6-ca0cedf7f2e9/public_url">view credential</a>
</p>
</div>
</section>
<section id="hobbies" class="section mt-3 mt-md-5 p-3">
<h3 class="mb-3 text-uppercase">Hobbies</h3>
<ul>
<li>Software Development</li>
<li>Learning new languages</li>
<li>Hiking</li>
<li>Travel</li>
<li>Cooking</li>
</ul>
</section>
</div>
</main>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.6.1.min.js" integrity="sha256-o88AwQnZB+VDvE9tvIXrMQaPlFFSUTR+nldQm1LuPXQ=" crossorigin="anonymous"></script>
<script src="js/scripts.js"></script>
</body>
</html>
I have reviewed many other articules, but still unsure what the problem is. I would be most appreciative for any help or suggestions. Thanks in advance.
It looks like the API that you are calling in the script.js is not the same as the API you have put in the postman.
API in script.js is https://pl8h7bxm3j.execute-api.us-east-1.amazonaws.com
and that in postman is https://pl8h7bxm3j.execute-api.us-east-1.amazonaws.com/Prod/visit/
. In the console log of your website the API in script.js is throwing a 403, which is in turn causing a CORS error as for 403 you have not enabled any CORS headers.