<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Gus</title>
    <description>The latest articles on DEV Community by Gus (@gusfeliciano).</description>
    <link>https://dev.to/gusfeliciano</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F845292%2F16c70820-a6e7-47a6-8d51-b54097842b0c.jpeg</url>
      <title>DEV Community: Gus</title>
      <link>https://dev.to/gusfeliciano</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gusfeliciano"/>
    <language>en</language>
    <item>
      <title>Automating the Cloud Resume Challenge: Implementing CI/CD with GitHub Actions</title>
      <dc:creator>Gus</dc:creator>
      <pubDate>Thu, 08 Aug 2024 17:34:15 +0000</pubDate>
      <link>https://dev.to/gusfeliciano/automating-the-cloud-resume-challenge-implementing-cicd-with-github-actions-4m36</link>
      <guid>https://dev.to/gusfeliciano/automating-the-cloud-resume-challenge-implementing-cicd-with-github-actions-4m36</guid>
      <description>&lt;h2&gt;
  
  
  Cloud Resume Challenge - Part 2
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In the first part of this series, we walked through building a cloud-native resume website using various AWS services. Now, we'll take our project to the next level by implementing Continuous Integration and Continuous Deployment (CI/CD) using GitHub Actions. This automation is crucial for maintaining and updating our cloud resume efficiently.&lt;/p&gt;

&lt;p&gt;CI/CD is a modern software development practice that emphasizes automating the stages of app development. In the context of our Cloud Resume Challenge, it means we can update our resume or make changes to our backend code, push these changes to GitHub, and have them automatically deployed to our AWS infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffl8it1vkgv22c7jhvaey.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffl8it1vkgv22c7jhvaey.png" alt="Image description" width="800" height="477"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why CI/CD Matters in Cloud Development
&lt;/h2&gt;

&lt;p&gt;Before we dive into the implementation, let's discuss why CI/CD is so important:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Consistency&lt;/strong&gt;: Automated deployments ensure that every change is applied consistently across your infrastructure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Efficiency&lt;/strong&gt;: Manual deployments are time-consuming and prone to human error. Automation saves time and reduces mistakes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rapid Iteration&lt;/strong&gt;: With CI/CD, new features and bug fixes can be deployed quickly and safely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Practices&lt;/strong&gt;: Implementing CI/CD encourages good development practices like frequent commits, comprehensive testing, and code reviews.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: As your project grows, CI/CD pipelines can easily scale to accommodate more complex deployment processes.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Setting Up the GitHub Repositories
&lt;/h2&gt;

&lt;p&gt;For this project, we'll use two separate repositories:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Frontend Repository&lt;/strong&gt;: Contains the HTML, CSS, and JavaScript files for the static website.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend Repository&lt;/strong&gt;: Houses the AWS CDK code for the Lambda function, API Gateway, and DynamoDB table.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This separation allows us to manage and version control our frontend and backend code independently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing CI/CD for the Frontend
&lt;/h2&gt;

&lt;p&gt;Let's start by setting up a GitHub Actions workflow for our frontend. Create a new file in your frontend repository at &lt;code&gt;.github/workflows/deploy-frontend.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy Frontend&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;main&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Configure AWS Credentials&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/configure-aws-credentials@v1&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;aws-access-key-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_ACCESS_KEY_ID }}&lt;/span&gt;
        &lt;span class="na"&gt;aws-secret-access-key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_SECRET_ACCESS_KEY }}&lt;/span&gt;
        &lt;span class="na"&gt;aws-region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-east-1&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to S3&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws s3 sync . s3://${{ secrets.S3_BUCKET }} --delete&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Invalidate CloudFront&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;aws cloudfront create-invalidation --distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} --paths "/*"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This workflow does the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Triggers on pushes to the main branch&lt;/li&gt;
&lt;li&gt;Sets up AWS credentials (which we'll configure in GitHub secrets)&lt;/li&gt;
&lt;li&gt;Syncs the repository contents to the S3 bucket&lt;/li&gt;
&lt;li&gt;Invalidates the CloudFront cache to ensure the latest version is served&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Implementing CI/CD for the Backend
&lt;/h2&gt;

&lt;p&gt;For the backend, we'll create a similar workflow. Create a new file in your backend repository at &lt;code&gt;.github/workflows/deploy-backend.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy Backend&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;main&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up Node.js&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v3&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;16'&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run tests&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm test&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Configure AWS Credentials&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/configure-aws-credentials@v1&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;aws-access-key-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_ACCESS_KEY_ID }}&lt;/span&gt;
        &lt;span class="na"&gt;aws-secret-access-key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_SECRET_ACCESS_KEY }}&lt;/span&gt;
        &lt;span class="na"&gt;aws-region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-east-1&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to AWS&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx cdk deploy --require-approval never&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Triggers on pushes to the main branch&lt;/li&gt;
&lt;li&gt;Sets up Node.js&lt;/li&gt;
&lt;li&gt;Installs dependencies&lt;/li&gt;
&lt;li&gt;Runs tests (which you should implement)&lt;/li&gt;
&lt;li&gt;Sets up AWS credentials&lt;/li&gt;
&lt;li&gt;Deploys the CDK stack&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Managing Secrets
&lt;/h2&gt;

&lt;p&gt;To keep our sensitive information secure, we'll use GitHub Secrets. Go to your repository settings, click on "Secrets and variables", then "Actions", and add the following secrets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AWS_ACCESS_KEY_ID&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AWS_SECRET_ACCESS_KEY&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;S3_BUCKET&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CLOUDFRONT_DISTRIBUTION_ID&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These secrets are securely encrypted and only exposed to the GitHub Actions workflow during execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Practices for CI/CD in Cloud-Native Applications
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Keep Secrets Secure&lt;/strong&gt;: Never hard-code sensitive information. Always use environment variables or a secrets management service.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Implement Robust Testing&lt;/strong&gt;: Include unit tests, integration tests, and end-to-end tests in your CI pipeline.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use Infrastructure as Code&lt;/strong&gt;: Define your infrastructure using tools like AWS CDK or CloudFormation. This ensures consistency and allows version control of your infrastructure.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Monitor Your Pipelines&lt;/strong&gt;: Set up notifications for failed deployments and regularly review your CI/CD logs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Implement Gradual Rollouts&lt;/strong&gt;: Consider using techniques like blue-green deployments or canary releases for safer deployments.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Challenges and Lessons Learned
&lt;/h2&gt;

&lt;p&gt;Implementing CI/CD wasn't without its challenges. Here are some lessons learned:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;IAM Permissions&lt;/strong&gt;: Ensure your AWS IAM user has the correct permissions for deployment. It may take some trial and error to get this right.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dependency Management&lt;/strong&gt;: Keep your dependencies up-to-date in the CI environment. Consider using tools like Dependabot to automate this process.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Testing is Crucial&lt;/strong&gt;: Invest time in writing comprehensive tests. They will save you from deploying bugs to production.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cost Management&lt;/strong&gt;: Be aware of the costs associated with your CI/CD pipeline, especially if you're running extensive tests or deployments frequently.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Implementing CI/CD with GitHub Actions has significantly streamlined our development process for the Cloud Resume Challenge. It allows us to focus on writing code and making improvements, knowing that deployment is just a git push away.&lt;/p&gt;

&lt;p&gt;This experience reinforces the importance of automation in cloud development and provides hands-on experience with industry-standard CI/CD practices. Whether you're working on a personal project or a large-scale application, investing time in setting up a robust CI/CD pipeline pays dividends in productivity and reliability.&lt;/p&gt;

&lt;p&gt;Remember, CI/CD is not a one-time setup. Continue to refine your pipelines, add more tests, and optimize your workflows as your project evolves. Happy coding and deploying!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>aws</category>
      <category>javascript</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Mastering Cloud Security: My Journey Deploying OWASP Juice Shop on AWS ECS</title>
      <dc:creator>Gus</dc:creator>
      <pubDate>Fri, 02 Aug 2024 18:12:27 +0000</pubDate>
      <link>https://dev.to/gusfeliciano/mastering-cloud-security-deploying-owasp-juice-shop-on-aws-ecs-4apn</link>
      <guid>https://dev.to/gusfeliciano/mastering-cloud-security-deploying-owasp-juice-shop-on-aws-ecs-4apn</guid>
      <description>&lt;p&gt;In the dynamic world of cybersecurity, I've found that hands-on experience is crucial. That's why I embarked on a project to deploy OWASP Juice Shop, an intentionally vulnerable web application, on Amazon Web Services (AWS) using Elastic Container Service (ECS). In this post, I'll share why I chose this project, my reasons for selecting AWS and ECS, and what I've learned along the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Learning Benefits of This Project
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Real-world Application&lt;/strong&gt;: OWASP Juice Shop isn't a simple "Hello World" app. It's a full-stack JavaScript web application mimicking a real e-commerce site, exposing me to vulnerabilities I might encounter in actual production environments.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hands-on Experience&lt;/strong&gt;: By deploying Juice Shop on AWS, I'm not just reading about cloud security - I'm actively implementing it. This practical experience has been invaluable for truly grasping the concepts and challenges involved.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Comprehensive Learning&lt;/strong&gt;: This project has allowed me to touch on multiple aspects of IT and security, including cloud services, containerization, networking, and web application security. It's been a holistic learning experience bridging several crucial domains in modern tech stacks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Safe Environment&lt;/strong&gt;: Juice Shop provides me with a legal and safe environment to practice ethical hacking and security testing. I can explore vulnerabilities without the risks associated with probing production systems.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why I Chose AWS
&lt;/h2&gt;

&lt;p&gt;I selected Amazon Web Services as my cloud platform for several reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Market Leader&lt;/strong&gt;: As the largest cloud provider, experience with AWS is highly valued in the job market.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Comprehensive Services&lt;/strong&gt;: AWS offers a vast array of services that allowed me to build a complete, production-like environment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Robust Documentation&lt;/strong&gt;: AWS's extensive documentation and learning resources made it easier for me to get started and deepen my knowledge.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scalability&lt;/strong&gt;: While my project starts small, AWS provides the capability to scale to enterprise-level deployments, allowing me to extrapolate my knowledge to larger scenarios.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  My Decision to Use ECS (Elastic Container Service)
&lt;/h2&gt;

&lt;p&gt;I chose ECS for container orchestration due to several advantages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Simplified Orchestration&lt;/strong&gt;: ECS abstracts away much of the complexity, allowing me to focus on deployment and security aspects.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Integration with AWS Services&lt;/strong&gt;: ECS integrates seamlessly with other AWS services, providing a cohesive learning experience within the AWS ecosystem.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fargate Option&lt;/strong&gt;: Using ECS with Fargate allows for serverless container deployment, reducing the operational overhead and allowing me to focus on the application and its security.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Industry Relevance&lt;/strong&gt;: Container orchestration is a highly sought-after skill, and experience with ECS provides me with valuable, transferable knowledge.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why I Opted for Scripts Instead of Infrastructure as Code (IaC)
&lt;/h2&gt;

&lt;p&gt;For this project, I decided to use shell scripts and JSON configuration files instead of IaC tools like CloudFormation, CDK, or Terraform. Here's why:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Learning Fundamentals&lt;/strong&gt;: Using scripts allowed me to understand the basic AWS CLI commands and API interactions, providing a solid foundation before moving to more abstract IaC tools.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Simplicity&lt;/strong&gt;: For a small-scale project like this, scripts offer a straightforward approach that's easy to understand and modify.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Direct Control&lt;/strong&gt;: Writing scripts gave me direct control over each step of the deployment process, which was beneficial for learning how each AWS service works.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Gradual Learning Curve&lt;/strong&gt;: This approach allowed me to gradually introduce AWS services and concepts without the additional complexity of learning an IaC tool simultaneously.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;While IaC tools would be preferable for larger, production-grade deployments due to their state management and reproducibility features, using scripts has been an excellent starting point for my learning journey.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I've Learned
&lt;/h2&gt;

&lt;p&gt;This project has offered me a wealth of learning opportunities:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cloud Architecture&lt;/strong&gt;: I've gained understanding in designing and implementing a secure cloud architecture using VPCs, subnets, and security groups.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Container Deployment&lt;/strong&gt;: I've learned how to deploy and manage containerized applications in a cloud environment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security Best Practices&lt;/strong&gt;: I've implemented and understood AWS security best practices, including the principle of least privilege with IAM roles.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Networking in the Cloud&lt;/strong&gt;: I've configured and managed networking in a cloud environment, including public and private subnets.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scripting and CLI Usage&lt;/strong&gt;: I've improved my scripting skills and become proficient with the AWS CLI.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Monitoring and Logging&lt;/strong&gt;: I've set up and used CloudWatch for monitoring the application and infrastructure.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Web Application Security&lt;/strong&gt;: I've gained hands-on experience with common web vulnerabilities by working through Juice Shop's challenges.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cost Management&lt;/strong&gt;: I've learned to understand AWS pricing models and optimize costs in cloud deployments.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Deploying OWASP Juice Shop on AWS ECS has been more than just a technical exercise - it's been a comprehensive learning journey touching on crucial aspects of modern application deployment and security. As an aspiring cybersecurity professional and cloud enthusiast, this project has provided me with valuable, hands-on experience that I'm sure will serve me well in my career.&lt;/p&gt;

&lt;p&gt;I recognize that the cloud and cybersecurity landscapes are constantly evolving. This project has provided me with a solid foundation, but I know my learning doesn't stop here. I plan to use this as a springboard to dive deeper into areas that interest me, stay updated with the latest developments, and continue to practice and expand my skills.&lt;/p&gt;

&lt;p&gt;Here's to continuous learning and staying secure!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>Building a Cloud-Native Website with AWS: The Cloud Resume Challenge</title>
      <dc:creator>Gus</dc:creator>
      <pubDate>Thu, 01 Aug 2024 21:10:49 +0000</pubDate>
      <link>https://dev.to/gusfeliciano/aws-cloud-resume-challenge-blog-post-part-1-559n</link>
      <guid>https://dev.to/gusfeliciano/aws-cloud-resume-challenge-blog-post-part-1-559n</guid>
      <description>&lt;h2&gt;
  
  
  AWS Cloud Resume Challenge Part 1
&lt;/h2&gt;



&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As a tech enthusiast and cloud professional looking to expand my AWS skills, I recently took on the Cloud Resume Challenge. This project, created by Forrest Brazeal, is an excellent opportunity for anyone – from beginners to experienced professionals – to gain hands-on experience with a variety of AWS services.&lt;/p&gt;

&lt;p&gt;The Cloud Resume Challenge is more than just a simple project; it's a comprehensive, real-world application of cloud technologies. Here's why it's such a valuable learning experience:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Practical Application&lt;/strong&gt;: You're not just learning theory; you're building a functional, cloud-native application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service Integration&lt;/strong&gt;: The challenge requires you to use multiple AWS services together, mimicking real-world scenarios.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full-Stack Development&lt;/strong&gt;: From frontend to backend, you'll touch every part of the application stack.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Practices&lt;/strong&gt;: The project encourages the use of Infrastructure as Code (IaC) and CI/CD pipelines, essential skills in modern cloud development.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Portfolio Building&lt;/strong&gt;: Upon completion, you have a tangible project to showcase to potential employers or clients.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this blog post, I'll walk you through my journey of completing the Cloud Resume Challenge, detailing each step, the AWS services used, and the valuable insights gained along the way. Whether you're new to AWS or looking to deepen your expertise, I hope my experience will inspire and guide you in your own cloud learning journey.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn8x26r9xurijqd053zbp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn8x26r9xurijqd053zbp.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Setting Up a Static Website with S3&lt;/li&gt;
&lt;li&gt;Securing the Website with CloudFront&lt;/li&gt;
&lt;li&gt;Configuring DNS with Route 53&lt;/li&gt;
&lt;li&gt;
Implementing a Visitor Counter

&lt;ul&gt;
&lt;li&gt;DynamoDB for Data Storage&lt;/li&gt;
&lt;li&gt;Lambda for Backend Logic&lt;/li&gt;
&lt;li&gt;API Gateway for HTTP Endpoints&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Frontend JavaScript Integration&lt;/li&gt;
&lt;li&gt;Testing the JavaScript Code&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Setting Up a Static Website with S3
&lt;/h2&gt;

&lt;p&gt;Amazon S3 (Simple Storage Service) is the foundation of our cloud resume. It's a highly scalable object storage service that can host static websites efficiently and cost-effectively. Here's a step-by-step guide on how to set it up:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create an S3 bucket:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Log into the AWS Management Console and navigate to S3.&lt;/li&gt;
&lt;li&gt;Click "Create bucket" and choose a globally unique name (e.g., "my-cloud-resume-yourname").&lt;/li&gt;
&lt;li&gt;In the bucket settings, enable "Static website hosting".&lt;/li&gt;
&lt;li&gt;Set the index document to "index.html".&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Upload your website files:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prepare your HTML resume. If you're not comfortable with HTML, you can use a template or convert your existing resume to HTML using online tools.&lt;/li&gt;
&lt;li&gt;Upload your HTML, CSS, and any JavaScript files to the bucket.&lt;/li&gt;
&lt;li&gt;Ensure the files have public read permissions.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Configure bucket policy:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the bucket permissions, add a bucket policy to allow public read access:&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PublicReadGetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::your-bucket-name/*"&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Replace "your-bucket-name" with your actual bucket name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why S3 for static website hosting?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scalability: S3 can handle any amount of traffic without you needing to manage servers.&lt;/li&gt;
&lt;li&gt;Cost-effective: You only pay for the storage you use and the data transferred.&lt;/li&gt;
&lt;li&gt;Simplicity: Easy to set up and requires minimal ongoing maintenance.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Securing the Website with CloudFront
&lt;/h2&gt;

&lt;p&gt;While S3 provides a solid foundation, CloudFront provides a Content Delivery Network (CDN) service. This not only improves the performance of our website but also adds an extra layer of security. Here's how to set it up:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create a CloudFront distribution:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the AWS Console, go to CloudFront and click "Create Distribution".&lt;/li&gt;
&lt;li&gt;Set the origin domain to your S3 bucket's website endpoint.&lt;/li&gt;
&lt;li&gt;Enable "Redirect HTTP to HTTPS" for added security.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Configure SSL/TLS certificate:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use AWS Certificate Manager (ACM) to create a free SSL/TLS certificate for your domain.&lt;/li&gt;
&lt;li&gt;In your CloudFront distribution settings, select this certificate.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Set up Origin Access Identity (OAI):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create an OAI and associate it with your distribution.&lt;/li&gt;
&lt;li&gt;Update your S3 bucket policy to only allow access from this OAI.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Why use CloudFront?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Improved Performance: CloudFront caches your content at edge locations worldwide, reducing latency for global visitors.&lt;/li&gt;
&lt;li&gt;Enhanced Security: HTTPS encryption and the ability to configure security headers.&lt;/li&gt;
&lt;li&gt;Cost Optimization: CloudFront can reduce your S3 data transfer costs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configuring DNS with Route 53
&lt;/h2&gt;

&lt;p&gt;Now that we have our website hosted and a CDN set up, we need to give it a user-friendly domain name. This is where Route 53, AWS's Domain Name System (DNS) web service, comes into play. Here's how to set it up:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create a hosted zone:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In Route 53, create a hosted zone for your domain.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Update name servers:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If your domain is registered elsewhere, update the name servers at your registrar to use Route 53's name servers.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create record sets:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create an A record for your domain, aliasing it to your CloudFront distribution.&lt;/li&gt;
&lt;li&gt;If needed, create a CNAME record for www subdomain.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Why use Route 53?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Integration: Seamless integration with other AWS services.&lt;/li&gt;
&lt;li&gt;Reliability: Backed by AWS's global infrastructure.&lt;/li&gt;
&lt;li&gt;Advanced Features: Health checks, traffic flow, and domain registration in one place.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementing a Visitor Counter
&lt;/h2&gt;

&lt;p&gt;Now comes the exciting part – adding dynamic functionality to our static website. We'll implement a visitor counter using a serverless architecture with DynamoDB, Lambda, and API Gateway. This showcases how even a simple static site can incorporate dynamic elements using cloud services.&lt;/p&gt;

&lt;h3&gt;
  
  
  DynamoDB for Data Storage
&lt;/h3&gt;

&lt;p&gt;DynamoDB is AWS's fully managed NoSQL database service. It's perfect for our use case due to its scalability and low latency. Here's how to set it up:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create a DynamoDB table:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Name: "VisitorCount"&lt;/li&gt;
&lt;li&gt;Partition key: "id" (String)&lt;/li&gt;
&lt;li&gt;Add an item with id "visitors" and an attribute "count" set to 0.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Why DynamoDB?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fully Managed: No servers to provision or manage.&lt;/li&gt;
&lt;li&gt;Scalability: Automatically scales to handle any amount of traffic.&lt;/li&gt;
&lt;li&gt;Performance: Single-digit millisecond latency at any scale.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Lambda for Backend Logic
&lt;/h3&gt;

&lt;p&gt;AWS Lambda allows us to run code without provisioning or managing servers. Our Lambda function will update the visitor count in DynamoDB. Here's how to set it up:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create a Lambda function:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Runtime: Node.js 20.x&lt;/li&gt;
&lt;li&gt;Code:&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DynamoDBClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;UpdateItemCommand&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-sdk/client-dynamodb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DynamoDBClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

   &lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="na"&gt;TableName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TABLE_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;visitors&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
           &lt;span class="na"&gt;UpdateExpression&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ADD visitorCount :inc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="na"&gt;ExpressionAttributeValues&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;:inc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;N&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
           &lt;span class="na"&gt;ReturnValues&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UPDATED_NEW&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
       &lt;span class="p"&gt;};&lt;/span&gt;

       &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UpdateItemCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
           &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

           &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;visitorCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Attributes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visitorCount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;N&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

           &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                   &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Access-Control-Allow-Origin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://yourdomain.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Access-Control-Allow-Headers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Access-Control-Allow-Methods&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;OPTIONS,POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
               &lt;span class="p"&gt;},&lt;/span&gt;
               &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;visitorCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;visitorCount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
           &lt;span class="p"&gt;};&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
           &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                   &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Access-Control-Allow-Origin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://yourdomain.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Access-Control-Allow-Headers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Access-Control-Allow-Methods&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;OPTIONS,POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
               &lt;span class="p"&gt;},&lt;/span&gt;
               &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed to update visitor count&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
           &lt;span class="p"&gt;};&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;};&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Set up environment variables:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add TABLE_NAME environment variable with your DynamoDB table name.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Configure permissions:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Give the Lambda function permission to read/write to your DynamoDB table.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Why Lambda?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pay per Use: You only pay for the compute time you consume.&lt;/li&gt;
&lt;li&gt;No Server Management: AWS handles all the infrastructure management.&lt;/li&gt;
&lt;li&gt;Automatic Scaling: Lambda automatically scales your application by running code in response to each trigger.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  API Gateway for HTTP Endpoints
&lt;/h3&gt;

&lt;p&gt;Amazon API Gateway acts as the "front door" for our Lambda function, allowing it to be triggered via HTTP requests. Here's how to set it up:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create a new API:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Choose HTTP API type for simplicity and cost-effectiveness.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create a resource and method:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a resource named "visitorcount".&lt;/li&gt;
&lt;li&gt;Add a POST method to this resource, integrating it with your Lambda function.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Enable CORS:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the API settings, enable CORS for your domain.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Deploy the API:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new stage (e.g., "prod") and deploy your API.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Why API Gateway?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Managed Service: No need to manage any infrastructure.&lt;/li&gt;
&lt;li&gt;Scalability: Handles any number of API calls simultaneously.&lt;/li&gt;
&lt;li&gt;Security: Provides authorization and access control.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frontend JavaScript Integration
&lt;/h2&gt;

&lt;p&gt;Now that our backend is set up, let's integrate it with our frontend:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Add HTML for the visitor counter:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

   &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"visitor-count"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Visitors: &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"count"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;0&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Add JavaScript to call our API:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

   &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateVisitorCount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://your-api-gateway-url/visitorcount&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
           &lt;span class="p"&gt;},&lt;/span&gt;
           &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cors&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
       &lt;span class="p"&gt;})&lt;/span&gt;
       &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
       &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;count&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visitorCount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="p"&gt;})&lt;/span&gt;
       &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DOMContentLoaded&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateVisitorCount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Replace '&lt;a href="https://your-api-gateway-url" rel="noopener noreferrer"&gt;https://your-api-gateway-url&lt;/a&gt;' with your actual API Gateway URL.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing the JavaScript Code
&lt;/h2&gt;

&lt;p&gt;Testing is a crucial part of any development process. For our visitor counter, we can use Jest, a popular JavaScript testing framework. Here's how to set it up:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Install Jest:&lt;/strong&gt;
```
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;npm install --save-dev jest&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
2. **Create a test file (e.g., `visitorCounter.test.js`):**

   ```javascript


   // Mock fetch function
   global.fetch = jest.fn(() =&amp;gt;
     Promise.resolve({
       json: () =&amp;gt; Promise.resolve({ visitorCount: 5 }),
     })
   );

   // Import the function to test
   const { updateVisitorCount } = require('./visitorCounter');

   test('updates visitor count correctly', async () =&amp;gt; {
     // Set up our document body
     document.body.innerHTML = '&amp;lt;div id="count"&amp;gt;0&amp;lt;/div&amp;gt;';

     // Call the function
     await updateVisitorCount();

     // Check that the count was updated
     expect(document.getElementById('count').textContent).toBe('5');
   });


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Run the tests:&lt;/strong&gt;
```
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;npx jest&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
This test mocks the fetch function to simulate an API call and checks if our updateVisitorCount function correctly updates the DOM with the returned count.

Additional testing examples could include:

- Testing error handling:
  ```javascript


  test('handles errors gracefully', async () =&amp;gt; {
    global.fetch.mockImplementationOnce(() =&amp;gt; Promise.reject("API is down"));

    console.error = jest.fn();

    await updateVisitorCount();

    expect(console.error).toHaveBeenCalled();
  });


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Testing with different response values:
```javascript
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;test('handles large numbers correctly', async () =&amp;gt; {&lt;br&gt;
    global.fetch.mockImplementationOnce(() =&amp;gt; &lt;br&gt;
      Promise.resolve({&lt;br&gt;
        json: () =&amp;gt; Promise.resolve({ visitorCount: 1000000 }),&lt;br&gt;
      })&lt;br&gt;
    );&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;document.body.innerHTML = '&amp;lt;div id="count"&amp;gt;0&amp;lt;/div&amp;gt;';
await updateVisitorCount();
expect(document.getElementById('count').textContent).toBe('1000000');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;});&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
These tests help ensure our visitor counter works correctly under various conditions, improving the reliability of our cloud resume.

## Conclusion

Completing the Cloud Resume Challenge is an excellent way to gain hands-on experience with a variety of AWS services. Throughout this project, we've touched on several key aspects of cloud computing:

1. **Static Web Hosting**: Using S3 to host our resume website.
2. **Content Delivery**: Implementing CloudFront to improve performance and security.
3. **DNS Management**: Configuring Route 53 for a custom domain.
4. **Serverless Computing**: Using Lambda for our backend logic.
5. **NoSQL Databases**: Utilizing DynamoDB for data storage.
6. **API Development**: Creating an API with API Gateway.
7. **Frontend Development**: Integrating our backend with JavaScript.
8. **Testing**: Implementing unit tests for our JavaScript code.

This challenge provides a comprehensive overview of building a cloud-native application, from frontend to backend. It's an excellent starting point for anyone looking to dive deeper into AWS services or to showcase their cloud skills to potential employers.

In the next part of this series, we'll explore how to automate the deployment of our cloud resume using CI/CD practices with GitHub Actions, further enhancing our cloud development skills.

Remember, the cloud is constantly evolving, and there's always more to learn. Keep exploring, keep building, and most importantly, keep challenging yourself!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>tutorial</category>
      <category>awschallenge</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
