<?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: Randika Madhushan Perera</title>
    <description>The latest articles on DEV Community by Randika Madhushan Perera (@randiakm).</description>
    <link>https://dev.to/randiakm</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%2F392119%2Fbf079ce5-b92e-4341-8672-ec54d93ed960.jpeg</url>
      <title>DEV Community: Randika Madhushan Perera</title>
      <link>https://dev.to/randiakm</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/randiakm"/>
    <language>en</language>
    <item>
      <title>Building a Scalable Pet Rehoming Platform with AWS Serverless Architecture</title>
      <dc:creator>Randika Madhushan Perera</dc:creator>
      <pubDate>Fri, 09 Jan 2026 09:49:08 +0000</pubDate>
      <link>https://dev.to/randiakm/building-a-scalable-pet-rehoming-platform-with-aws-serverless-architecture-195b</link>
      <guid>https://dev.to/randiakm/building-a-scalable-pet-rehoming-platform-with-aws-serverless-architecture-195b</guid>
      <description>&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;PawReHome&lt;/em&gt; is a modern, full-featured pet rehoming platform that connects loving families with pets in need. Build with a serverless-first approach, the platform leverages AWS managed services to provide a scalable, cost-effective and secure solution for animal rescue organizations and induvial users. &lt;/p&gt;

&lt;p&gt;This article explores the AWS architecture behind the PawReHome, how several AWS services work together to create a robust, role based access control, real-time data management. &lt;/p&gt;

&lt;h3&gt;
  
  
  Project Overview
&lt;/h3&gt;

&lt;p&gt;PawReHome is a application fully integrated with AWS backend services. The platform supports:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User authentication and authorization with role-based access control&lt;/li&gt;
&lt;li&gt;Multi-tenant organization management for rescue groups&lt;/li&gt;
&lt;li&gt;Pet listing management with approval workflows&lt;/li&gt;
&lt;li&gt;Image upload for pet photos&lt;/li&gt;
&lt;li&gt;Adoption applications and inquiry systems&lt;/li&gt;
&lt;li&gt;Platform administration for content moderation &lt;/li&gt;
&lt;li&gt;Featured pets curation for homepage visibility&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  AWS Architecture Overview
&lt;/h3&gt;

&lt;p&gt;This utilizes a serverless architecture that eliminates server management overhead and provides automatic scaling. &lt;/p&gt;

&lt;p&gt;Complete AWS services stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS Amplify: Frontend hosting, CI/CD and deployment&lt;/li&gt;
&lt;li&gt;Amazon Cognito: User authentication and authorization&lt;/li&gt;
&lt;li&gt;AWS Lambda: Serverless backend functions&lt;/li&gt;
&lt;li&gt;Amazon API Gateway: RESTFUL API management and routing &lt;/li&gt;
&lt;li&gt;DynamoDB: NoSQL database for all application data&lt;/li&gt;
&lt;li&gt;S3: Object storage for pet images&lt;/li&gt;
&lt;li&gt;IAM: Identity and access management&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Architecture Flow
&lt;/h3&gt;

&lt;h4&gt;
  
  
  High-Level Architecture Diagram
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fzhy2coz5u8bb761icix9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fzhy2coz5u8bb761icix9.png" alt="High-Level Architecture Diagram" width="800" height="468"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Deep Dive: AWS Services Implementation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. AWS Amplify - Frontend Hosting &amp;amp; CI/CD&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Purpose: As you can see Amplify hosts the Next.js frontend application and provides continues deployment capabilities. &lt;/p&gt;

&lt;p&gt;Implementation Details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The amplify.yml configuration defines the build process&lt;/li&gt;
&lt;li&gt;Automatic builds triggered on Git commits&lt;/li&gt;
&lt;li&gt;Environment variables managed through Amplify Console&lt;/li&gt;
&lt;li&gt;Global CDN ensures low latency worldwide&lt;/li&gt;
&lt;li&gt;Built-in SSL certificate provisioning via AWS Certificate Manager&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Benefits of the Amplify&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zero server management, you do not need to worry about.&lt;/li&gt;
&lt;li&gt;Automatic scaling when traffic spikes.&lt;/li&gt;
&lt;li&gt;Preview deployment.&lt;/li&gt;
&lt;li&gt;Rollback capabilities when you have an issue. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Cognito - Authentication &amp;amp; Authorization&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Cognito provides secure user access and authentication across your application. This has role-based access control (RBAC) thorough Cognito groups. &lt;/p&gt;

&lt;p&gt;Let me explain the Authorization Flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User logs in via Cognito&lt;/li&gt;
&lt;li&gt;Cognito issues JWT token with user claims&lt;/li&gt;
&lt;li&gt;Token includes cognito:groups claim with user's groups&lt;/li&gt;
&lt;li&gt;API Gateway validates token&lt;/li&gt;
&lt;li&gt;Lambda functions check group membership for authorization&lt;/li&gt;
&lt;li&gt;DynamoDB queries are filtered based on user permissions&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;3. Lambda - Serverless Backend Functions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AWS Lambda functions handle all the business logic, data processing and API responses without managing servers. How relief :) &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example Lambda function (pet listing):&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { DynamoDBClient } = require("@aws-sdk/client-dynamodb");
const { DynamoDBDocumentClient, PutCommand, ScanCommand } = require("@aws-sdk/lib-dynamodb");

const docClient = DynamoDBDocumentClient.from(new DynamoDBClient({}));
const TABLE_NAME = "PawReHome-Pets";

exports.handler = async (event) =&amp;gt; {
  // Handle pet rehoming submission
  if (event.httpMethod === "POST") {
    const pet = {
      id: uuidv4(),
      ...JSON.parse(event.body),
      status: "pending",
      createdAt: new Date().toISOString()
    };

    await docClient.send(new PutCommand({
      TableName: TABLE_NAME,
      Item: pet
    }));

    return { statusCode: 201, body: JSON.stringify(pet) };
  }

  // Get approved pets
  if (event.httpMethod === "GET") {
    const result = await docClient.send(new ScanCommand({
      TableName: TABLE_NAME,
      FilterExpression: "#status = :status",
      ExpressionAttributeNames: { "#status": "status" },
      ExpressionAttributeValues: { ":status": "approved" }
    }));

    return { statusCode: 200, body: JSON.stringify(result.Items) };
  }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Amazon API Gateway - RESTful API Management&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;API gateway servers as the front door for all backend API requests, providing routing, authentication and rate limiting. (Do not forget about the rate limit, your pocket will empty 😉 and will have some concerns. 🛡️)&lt;/p&gt;

&lt;p&gt;API Gateway Configuration:&lt;/p&gt;

&lt;p&gt;REST API endpoint&lt;br&gt;
CORS enabled for frontend cross-origin requests&lt;br&gt;
Cognito Authorizer for automatic JWT validation&lt;br&gt;
Lambda Proxy Integration for seamless function invocation&lt;br&gt;
Stage Variables for environment management&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. DynamoDB - NoSQL Database&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;DynamoDB stores all application data with single-digit millisecond latency and automatic scaling. &lt;/p&gt;

&lt;p&gt;Table Design as below:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;PawReHome-Pets&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Partition Key: id (String)
Attributes: name, species, breed, age, size, gender, description, 
           images[], userId, organizationId, status, featured, 
           createdAt, updatedAt
GSIs:
  - UserIdIndex (userId) - Query user's pets
  - OrgIdIndex (organizationId) - Query organization's pets
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;PawReHome-Organizations&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Partition Key: id (String)
Attributes: name, slug, email, phone, description, logo, 
           status, verified, createdAt, reviewedBy, reviewedAt
GSIs:
  - SlugIndex (slug) - Query by URL slug
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;PawReHome-OrgMembers&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Partition Key: organizationId (String)
Sort Key: userId (String)
Attributes: role (admin/member), joinedAt, invitedBy
GSIs:
  - UserIdIndex (userId) - Query user's organizations
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;PawReHome-Applications&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Partition Key: id (String)
Attributes: petId, userId, status, applicantInfo, 
           submittedAt, reviewedAt
GSIs:
  - UserIdIndex (userId) - Query user's applications
  - PetIdIndex (petId) - Query pet's applications
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;PawReHome-Questions&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Partition Key: id (String)
Attributes: petId, userId, status, applicantInfo, 
           submittedAt, reviewedAt
GSIs:
  - UserIdIndex (userId) - Query user's applications
  - PetIdIndex (petId) - Query pet's applications
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;PawReHome-Favorites&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Partition Key: userId (String)
Sort Key: petId (String)
Attributes: addedAt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6. S3 - Image Storage&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;S3 uses to stores pet photos with public read access for displaying images on the website. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;to be continued.....&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Made with ❤️ for pets everywhere&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>lambda</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Building a Full-Stack E-Commerce Platform with AWS</title>
      <dc:creator>Randika Madhushan Perera</dc:creator>
      <pubDate>Sat, 27 Dec 2025 10:59:22 +0000</pubDate>
      <link>https://dev.to/randiakm/building-a-full-stack-e-commerce-platform-with-aws-3hki</link>
      <guid>https://dev.to/randiakm/building-a-full-stack-e-commerce-platform-with-aws-3hki</guid>
      <description>&lt;h3&gt;
  
  
  A Technical Deep-Dive into Modern Serverless Architecture
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Introduction
&lt;/h4&gt;

&lt;p&gt;I recently build an e-commerce website that handles custom gifts orders with image uploads, payment processing, order tracking, and admin dashboard and all running on a completely serverless architecture. This blog walks through the complete technical decisions, architecture patterns and lessons learned. &lt;/p&gt;

&lt;h4&gt;
  
  
  The Tech Stack that I used
&lt;/h4&gt;

&lt;p&gt;Layer: Frontend Framework&lt;br&gt;
Technology: Next.js 15&lt;br&gt;
Why I choose it: Server components, built in API routs&lt;/p&gt;

&lt;p&gt;Layer: Database&lt;br&gt;
Technology: Amazon DynamoDB&lt;br&gt;
Why I choose it: Serverless, pay-per-request, automatic scaling &lt;/p&gt;

&lt;p&gt;Layer: File Storage&lt;br&gt;
Technology: S3&lt;br&gt;
Why I choose it: Reliable, cheap, presigned URLs for secure access&lt;/p&gt;

&lt;p&gt;Layer: Authentication&lt;br&gt;
Technology: Cognito&lt;br&gt;
Why I choose it: Managed auth, MFA support, integrates with Amplify&lt;/p&gt;

&lt;p&gt;Layer: Email Service&lt;br&gt;
Technology: Amazon SES&lt;br&gt;
Why I choose it: Transactional emails, high deliverability, low cost&lt;/p&gt;

&lt;p&gt;Layer: Hosting&lt;br&gt;
Technology: Amazon Amplify Gen 2&lt;br&gt;
Why I choose it: Git based deployment, automates SSL, CDN included.&lt;/p&gt;

&lt;h4&gt;
  
  
  Architecture Overview
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fqdimqg7r9f3dtyx71k1k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fqdimqg7r9f3dtyx71k1k.png" alt="High level arch" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  The Customer Journey
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F8umqo4g6osmeg2qkol4j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F8umqo4g6osmeg2qkol4j.png" alt="The Customer Journey" width="800" height="69"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step by Step:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Landing Page - Customer learns about the product and clicks "Order Now"&lt;/li&gt;
&lt;li&gt;Customization - Customer writes their custom message and optionally uploads a photo&lt;/li&gt;
&lt;li&gt;Address Entry - Customer enters recipient shipping address and their billing details&lt;/li&gt;
&lt;li&gt;Payment - Redirected to Payment Gateway&lt;/li&gt;
&lt;li&gt;Success - After payment, customer sees their order ID and tracking link&lt;/li&gt;
&lt;li&gt;Email - Customer receives confirmation email with order details&lt;/li&gt;
&lt;li&gt;Tracking - Customer can check order status anytime using their order ID&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Payment Flow (The Tricky Part)
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Ffnx52eqo5qvbsv8aqs24.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Ffnx52eqo5qvbsv8aqs24.png" alt="Payment Flow" width="800" height="694"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Image Upload Architecture
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fk3ja6bpjtfroisj5hl5o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fk3ja6bpjtfroisj5hl5o.png" alt="Image Upload Architecture" width="800" height="148"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Why I Used Presigned URLs?
&lt;/h4&gt;

&lt;p&gt;Instead of making the S3 bucket public, I use presigned URLs that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expire after 1 hour&lt;/li&gt;
&lt;li&gt;Are generated on-demand&lt;/li&gt;
&lt;li&gt;Keep the bucket private and secure&lt;/li&gt;
&lt;li&gt;Work with CloudFront CDN&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Email Notification System
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fo9ao2s09402kof8tg3kf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fo9ao2s09402kof8tg3kf.png" alt="Email Notification System" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Email Features&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTML templates with incline CSS for email client compatibility&lt;/li&gt;
&lt;li&gt;Multiple admin recipients&lt;/li&gt;
&lt;li&gt;Reply-to headers, so admin can respond directly to customers&lt;/li&gt;
&lt;li&gt;Order details formatted for easy reading and fulfillment&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Deployment Pipeline
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F1e1iadh2ww8wc39epkzc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F1e1iadh2ww8wc39epkzc.png" alt="Deployment Pipeline" width="800" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The entire deployment is automated, &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Push the code to GitHub&lt;/li&gt;
&lt;li&gt;Amplify detects the change&lt;/li&gt;
&lt;li&gt;Builds the Next.js application&lt;/li&gt;
&lt;li&gt;Injects environment variables&lt;/li&gt;
&lt;li&gt;Deploys to CloudFront CDN&lt;/li&gt;
&lt;li&gt;Site is live in 305 minutes&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Deep Dive: AWS Services Powering This Application
&lt;/h2&gt;

&lt;h4&gt;
  
  
  AWS Services Architecture
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fae0mtdxhez4acdqbg4nb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fae0mtdxhez4acdqbg4nb.png" alt="AWS Services Architecture" width="800" height="713"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. AWS Amplify Gen 2&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What is it?&lt;/p&gt;

&lt;p&gt;AWS Amplify Gen 2 is a complete development platform that handles hosting, CI/CD, and backend infrastructure for web applications. It's the second generation of Amplify. &lt;/p&gt;

&lt;p&gt;Why I chose it? &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Git based deployments: Push to GitHub --&amp;gt; Automatically deployed into AWS&lt;/li&gt;
&lt;li&gt;Built in CI/CD: No Jenkins, No GitHub Actions&lt;/li&gt;
&lt;li&gt;Free SSL certificates: HTTPS enabled automatically&lt;/li&gt;
&lt;li&gt;Global CDN: CloudFront is included&lt;/li&gt;
&lt;li&gt;Custom domains: Easy DNS configurations&lt;/li&gt;
&lt;li&gt;Environment variables: Secure secrets management&lt;/li&gt;
&lt;li&gt;Preview Deployment: Test PRs before merging&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;How It's Used in This Project&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fuzmmvb3l4gpctovgyft8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fuzmmvb3l4gpctovgyft8.png" alt="Used in This Project" width="800" height="95"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Amazon DynamoDB&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What is it? &lt;/p&gt;

&lt;p&gt;DynamoDB is a fully managed NoSQL database service that provides single-digit millisecond performance at any scale. It's serverless, no provisioning, no patching or management required. &lt;/p&gt;

&lt;p&gt;Why I chose it? &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Serverless, Auto-scaling&lt;/li&gt;
&lt;li&gt;Pay-per request&lt;/li&gt;
&lt;li&gt;Single digit ms latency&lt;/li&gt;
&lt;li&gt;AWS-native integration&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;3. Amazon S3&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What is it? &lt;/p&gt;

&lt;p&gt;S3 is object storage built for storing and retrieving any amount of data. It's the backbone of AWS storage. &lt;/p&gt;

&lt;p&gt;Why I chose it?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Unlimited storage&lt;/li&gt;
&lt;li&gt;Presigned URLs&lt;/li&gt;
&lt;li&gt;Cheap&lt;/li&gt;
&lt;li&gt;Direct SDK access&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;S3 Features Used&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Private Bucket: Images not publicly accessible&lt;/li&gt;
&lt;li&gt;Presigned URLs: Temporary access links (1 hour)&lt;/li&gt;
&lt;li&gt;Server-side Upload: API route handles upload, not browser&lt;/li&gt;
&lt;li&gt;Content-Type: Proper MIME types for images&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Security Configuration&lt;/p&gt;

&lt;p&gt;Bucket Policy: Private by default&lt;br&gt;
CORS: Enabled for upload endpoints&lt;br&gt;
Presigned URLs: Time-limited access&lt;br&gt;
IAM: Scoped permissions for put/get only&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Amazon Cognito&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What is it? &lt;/p&gt;

&lt;p&gt;Amazon Cognito provides authentication, authorization and user management for web and mobile apps. Users can sign in directly or through third party identity providers. &lt;/p&gt;

&lt;p&gt;Why I chose it? &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;AWS-native&lt;/li&gt;
&lt;li&gt;MFA support&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;How It's Used&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Ffxso4avzhmrsr2sc1wl2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Ffxso4avzhmrsr2sc1wl2.png" alt="cognito works" width="800" height="669"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Amazon SES (Simple Email Service)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What is it? &lt;/p&gt;

&lt;p&gt;Amazon SES is a cloud based email service for sending transactional, marketing and notification emails. &lt;/p&gt;

&lt;p&gt;How It's Used&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fxgm8w2pa0ml5nexs2l0p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fxgm8w2pa0ml5nexs2l0p.png" alt="email used" width="800" height="572"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Amazon CloudFront (via Amplify)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What is it? &lt;/p&gt;

&lt;p&gt;CloudFront is a content delivery network that delivers content with low latency from 400+ edge locations worldwide. &lt;/p&gt;

&lt;p&gt;How It's Used&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fucaqq6gm54la0hprb17g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fucaqq6gm54la0hprb17g.png" alt="Cloudfront Used" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>nextjs</category>
      <category>cloudnative</category>
    </item>
    <item>
      <title>Terraform-CodeGen0: A Terraform Code Generator</title>
      <dc:creator>Randika Madhushan Perera</dc:creator>
      <pubDate>Sun, 12 Jan 2025 20:58:48 +0000</pubDate>
      <link>https://dev.to/randiakm/terraform-codegen0-a-terraform-code-generator-55aa</link>
      <guid>https://dev.to/randiakm/terraform-codegen0-a-terraform-code-generator-55aa</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/github"&gt;GitHub Copilot Challenge &lt;/a&gt;: New Beginnings&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;When we are deploying an application, especially in a cloud environment, we often need to manage the various infrastructure components, such as VPC, Servers, Databases, CDN, etc. Doing this manually is somewhat time-consuming and challenging. To overcome this, we can use terraform. &lt;/p&gt;

&lt;p&gt;Terraform allows the development of the architecture that deploys the application in a cloud environment. &lt;/p&gt;

&lt;p&gt;But writing the terraform is also somewhat time-consuming we need to create those codes manually, plus we need to know the terraform. &lt;/p&gt;

&lt;p&gt;Using this &lt;strong&gt;Terraform-CodeGen0&lt;/strong&gt; you can easily generate the terraform codes. All you need to input the VPC name, Subnets, Route Tabels, IGW, and NAT details into this application. This &lt;strong&gt;Terraform-CodeGen0&lt;/strong&gt; provides your terraform code. &lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/wtaEJJ3XcZc"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Repo
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/RandiakM" rel="noopener noreferrer"&gt;
        RandiakM
      &lt;/a&gt; / &lt;a href="https://github.com/RandiakM/Terraform-CodeGen0" rel="noopener noreferrer"&gt;
        Terraform-CodeGen0
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      GitHub Copilot 1-Day Build Challenge: This is a Terraform Code generation application for VPC
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;VPC Terraform Generator&lt;/h1&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Introduction&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;The VPC Terraform Generator is a tool designed to generate Terraform code for AWS infrastructure components such as VPCs, Subnets, Route Tables, Internet Gateways (IGWs), and NAT Gateways. This project uses a microservices architecture and is hosted on Netlify, with MongoDB as the database.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;How to Use&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;The VPC Terraform Generator allows users to generate Terraform code for various AWS components through a web interface. Users can input the necessary details for each component, and the application will generate the corresponding Terraform code.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Installation Steps&lt;/h2&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Clone the repository:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;git clone https://github.com/your-repo/vpc-terraform-generator.git
cd vpc-terraform-generator
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start="2"&gt;
&lt;li&gt;Install backend dependencies:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;cd api
npm install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start="3"&gt;
&lt;li&gt;Install frontend dependencies:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;cd ../frontend
npm install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start="4"&gt;
&lt;li&gt;Set up environment variables: Create a .env file in the api directory with the following content:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;MONGODB_URI=your_mongodb_connection_string
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start="5"&gt;
&lt;li&gt;Start the backend server:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;cd ../api
npm run dev
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start="6"&gt;
&lt;li&gt;Start the frontend server:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;cd ../frontend
npm start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Netlify Hosting Steps&lt;/h2&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a…&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/RandiakM/Terraform-CodeGen0" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Copilot Experience
&lt;/h2&gt;

&lt;p&gt;So for the initial start, I have used the below prompt to get an idea of this project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Build a Terraform code generator for AWS infrastructure components (VPCs, Subnets, Route Tables, IGWs, NAT, etc.) using a microservices architecture. The application will be hosted on Netlify, and MongoDB will be used as the database.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;Starting project structure:&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fym5qxjxdc5946b9qfde5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fym5qxjxdc5946b9qfde5.jpg" alt="Starting project structure" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Terraform Code Generation:&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ask to implement the utility functions to generate Terraform code-based user inputs for each resource type. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fihmk1erd3ttjkqj3ek0j.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fihmk1erd3ttjkqj3ek0j.jpg" alt="image 01" width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Edits:&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fknymzmzkk39kni49txjw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fknymzmzkk39kni49txjw.jpg" alt="image 02" width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Auto Complete:&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For this code auto-completion, I provide the description as a comment and start to create the function, then Copilot starts suggesting the code sections that are related to my task.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fj15dvna2cty465hv8ux4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fj15dvna2cty465hv8ux4.png" alt="auto complete" width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Documentation Creation:&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Used the below prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@workspace create a README with the below details:

1. Introduction 
2. How to use 
3. Installation Steps 
4. Netlify Hosting Steps 
5. User guide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Through this challenge and the journey, Copilot was an AI pair programmer who helped me build this application. From the start and even from the ending of this project Copilot was really helped me. &lt;/p&gt;

&lt;p&gt;Copilot reviewed the codes and provide alternative solutions to overcome some issues when developing this application. &lt;/p&gt;

&lt;p&gt;With the help of Copilot I was able to create this amazing application within just 24 hours, Wihtout copilot help this may take long. &lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>githubchallenge</category>
      <category>webdev</category>
      <category>ai</category>
    </item>
    <item>
      <title>Configuring AWS WAF, CloudFront, and S3 Bucket for Secure Access</title>
      <dc:creator>Randika Madhushan Perera</dc:creator>
      <pubDate>Fri, 03 Jan 2025 08:49:10 +0000</pubDate>
      <link>https://dev.to/randiakm/configuring-aws-waf-cloudfront-and-s3-bucket-for-secure-access-24a3</link>
      <guid>https://dev.to/randiakm/configuring-aws-waf-cloudfront-and-s3-bucket-for-secure-access-24a3</guid>
      <description>&lt;p&gt;How to Set Up AWS WAF, CloudFront and an S3 Bucket to serve content securely and Restrict content Access to certain originating sources only. This guide looks at some issues, for instance, 403 Forbidden, in order to troubleshoot the problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Objective&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The purpose of this assignment is to deploy AWS WAF, CloudFront and S3 bucket:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Restrict Access to certain origins, for example, &lt;a href="https://dev.test.com" rel="noopener noreferrer"&gt;https://dev.test.com&lt;/a&gt; and &lt;a href="https://int.test.com" rel="noopener noreferrer"&gt;https://int.test.com&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;When the CloudFront distribution is accessed, the index.html page should be served by default.&lt;/li&gt;
&lt;li&gt;To prevent unauthorized access and to correct common errors.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. You will require.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And AWS S3 bucket called, sample-bucket, where the files for the static website are stored.&lt;/p&gt;

&lt;p&gt;An AWS CloudFront distribution created with OAC linked to the S3 bucket.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Configuration Steps&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Step 1: Make Sure S3 Bucket Policy has below&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the S3 Console.&lt;/li&gt;
&lt;li&gt;Select your bucket (e.g., sample-bucket).&lt;/li&gt;
&lt;li&gt;Check the following bucket policy to allow access from CloudFront:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "AllowCloudFrontServicePrincipal",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::sample-bucket/*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "arn:aws:cloudfront::AWS_ACC_ID:distribution/CLOUDFRONT_ID"
                }
            }
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;Step 2: Configure CORS for the S3 Bucket&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the S3 Console, go to the Permissions tab.&lt;/li&gt;
&lt;li&gt;Edit the CORS configuration and set the following:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[
    {
        "AllowedHeaders": ["*"],
        "AllowedMethods": ["GET", "HEAD", "PUT", "POST", "DELETE"],
        "AllowedOrigins": [
            "https://dev.test.com",
            "https://int.test.com"
        ]
    }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Replace AllowedOrigins with your allowed domains.&lt;/li&gt;
&lt;li&gt;Restrict AllowedHeaders to necessary headers for production.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Step 3: Configure AWS WAF&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create WAF Rules:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the AWS WAF Console and select your Web ACL.&lt;/li&gt;
&lt;li&gt;Add the following rules:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Rule 1: Allow-Traffic&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Description: Allows requests from specific origins.&lt;/li&gt;
&lt;li&gt;Rule Definition:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "Name": "Allow-Traffic",
    "Priority": 1,
    "Statement": {
        "OrStatement": {
            "Statements": [
                {
                    "ByteMatchStatement": {
                        "SearchString": "https://dev.test.com",
                        "FieldToMatch": {
                            "SingleHeader": {
                                "Name": "origin"
                            }
                        },
                        "TextTransformations": [
                            {
                                "Priority": 0,
                                "Type": "NONE"
                            }
                        ],
                        "PositionalConstraint": "EXACTLY"
                    }
                },
                {
                    "ByteMatchStatement": {
                        "SearchString": "https://int.test.com",
                        "FieldToMatch": {
                            "SingleHeader": {
                                "Name": "origin"
                            }
                        },
                        "TextTransformations": [
                            {
                                "Priority": 0,
                                "Type": "NONE"
                            }
                        ],
                        "PositionalConstraint": "EXACTLY"
                    }
                }
            ]
        }
    },
    "Action": {
        "Allow": {}
    },
    "VisibilityConfig": {
        "SampledRequestsEnabled": true,
        "CloudWatchMetricsEnabled": true,
        "MetricName": "Allow-Traffic"
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rule 2: Block-All-Other-Traffic&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Description: Blocks all requests that don’t match the allowed origins.&lt;/li&gt;
&lt;li&gt;Rule Definition:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "Name": "Block-All-Other-Traffic",
    "Priority": 2,
    "Statement": {
        "NotStatement": {
            "Statement": {
                "OrStatement": {
                    "Statements": [
                        {
                            "ByteMatchStatement": {
                                "SearchString": "https://dev.test.com",
                                "FieldToMatch": {
                                    "SingleHeader": {
                                        "Name": "origin"
                                    }
                                },
                                "TextTransformations": [
                                    {
                                        "Priority": 0,
                                        "Type": "NONE"
                                    }
                                ],
                                "PositionalConstraint": "EXACTLY"
                            }
                        },
                        {
                            "ByteMatchStatement": {
                                "SearchString": "https://int.test.com",
                                "FieldToMatch": {
                                    "SingleHeader": {
                                        "Name": "origin"
                                    }
                                },
                                "TextTransformations": [
                                    {
                                        "Priority": 0,
                                        "Type": "NONE"
                                    }
                                ],
                                "PositionalConstraint": "EXACTLY"
                            }
                        }
                    ]
                }
            }
        }
    },
    "Action": {
        "Block": {}
    },
    "VisibilityConfig": {
        "SampledRequestsEnabled": true,
        "CloudWatchMetricsEnabled": true,
        "MetricName": "Block-All-Other-Traffic"
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Testing and Verification&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Test Allowed Origins&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -X GET https://cloudfront_domain_name \
     -H "Origin: https://dev.test.com" \
     -v
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected Result: HTTP 200 OK.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Test Disallowed Origins&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -X GET https://cloudfront_domain_name \
     -H "Origin: https://unauthorized.com" \
     -v
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected Result: HTTP 403 Forbidden.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Check WAF Logs&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Enable logging for the Web ACL in the AWS WAF Console.&lt;/li&gt;
&lt;li&gt;Monitor logs in CloudWatch to verify rule matches.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>aws</category>
      <category>waf</category>
      <category>cloudfront</category>
      <category>s3</category>
    </item>
    <item>
      <title>Full Stack Application Hosting in AWS</title>
      <dc:creator>Randika Madhushan Perera</dc:creator>
      <pubDate>Mon, 30 Dec 2024 16:09:30 +0000</pubDate>
      <link>https://dev.to/randiakm/full-stack-application-hosting-in-aws-2kc3</link>
      <guid>https://dev.to/randiakm/full-stack-application-hosting-in-aws-2kc3</guid>
      <description>&lt;h2&gt;
  
  
  Todo Application Documentation
&lt;/h2&gt;

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

&lt;ol&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Architecture Overview&lt;/li&gt;
&lt;li&gt;Backend Setup&lt;/li&gt;
&lt;li&gt;Frontend Setup&lt;/li&gt;
&lt;li&gt;AWS Configuration&lt;/li&gt;
&lt;li&gt;Deployment&lt;/li&gt;
&lt;li&gt;Troubleshooting&lt;/li&gt;
&lt;li&gt;Maintenance and Updates&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. Introduction
&lt;/h2&gt;

&lt;p&gt;This document provides a comprehensive guide for setting up, deploying, and maintaining a full-stack Todo application using Node.js, React, Express, and MongoDB. The application is deployed on AWS, utilizing services such as Lambda, API Gateway, S3, and CloudFront.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Architecture Overview
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Backend: Node.js with Express, deployed as an AWS Lambda function&lt;/li&gt;
&lt;li&gt;Frontend: React, built with Vite, hosted on S3 and served via CloudFront&lt;/li&gt;
&lt;li&gt;Database: MongoDB Atlas&lt;/li&gt;
&lt;li&gt;API: AWS API Gateway&lt;/li&gt;
&lt;li&gt;Authentication: (To be implemented)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Backend Setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3.1 Lambda Function
&lt;/h3&gt;

&lt;p&gt;Create a new file named &lt;code&gt;index.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&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="nx"&gt;mongoose&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;mongoose&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;cachedDb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;connectToDatabase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cachedDb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;cachedDb&lt;/span&gt;&lt;span class="p"&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;connection&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;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&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;MONGODB_URI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;useNewUrlParser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;useUnifiedTopology&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;cachedDb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&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;todoSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;updatedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="p"&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;Todo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Todo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;todoSchema&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;corsHeaders&lt;/span&gt; &lt;span class="o"&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;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="s1"&gt;https://your-cloudfront-domain.cloudfront.net&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;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="s1"&gt;Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token&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;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="s1"&gt;GET,POST,PUT,DELETE,OPTIONS&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;Access-Control-Allow-Credentials&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;true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;if &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="nx"&gt;httpMethod&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;OPTIONS&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="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="nx"&gt;corsHeaders&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;message&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 preflight request successful&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="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;connectToDatabase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;httpMethod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pathParameters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;{httpMethod} &lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;{resource}`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET /todos&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;todos&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;Todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&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="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;corsHeaders&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;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="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
        &lt;span class="p"&gt;};&lt;/span&gt;

      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST /todos&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;newTodo&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;Todo&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;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&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;savedTodo&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;newTodo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&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;201&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="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;corsHeaders&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;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="nx"&gt;savedTodo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
        &lt;span class="p"&gt;};&lt;/span&gt;

      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PUT /todos/{id}&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;updatedTodo&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;Todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findByIdAndUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nx"&gt;pathParameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;updatedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&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="na"&gt;new&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;updatedTodo&lt;/span&gt;&lt;span class="p"&gt;)&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;404&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="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;corsHeaders&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;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;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Todo not found&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="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="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;corsHeaders&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;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="nx"&gt;updatedTodo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
        &lt;span class="p"&gt;};&lt;/span&gt;

      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DELETE /todos/{id}&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;deletedTodo&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;Todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findByIdAndDelete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pathParameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;deletedTodo&lt;/span&gt;&lt;span class="p"&gt;)&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;404&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="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;corsHeaders&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;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;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Todo not found&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="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="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;corsHeaders&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;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;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Todo deleted successfully&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="nl"&gt;default&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;400&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="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;corsHeaders&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;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;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid request&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;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="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;corsHeaders&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;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;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Internal server error&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;h3&gt;
  
  
  3.2 Package Configuration
&lt;/h3&gt;

&lt;p&gt;Create a &lt;code&gt;package.json&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"todo-api-lambda"&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;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Todo API Lambda Function"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&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;"mongoose"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^6.0.0"&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;h3&gt;
  
  
  3.3 Deployment Package
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Install dependencies: &lt;code&gt;npm install&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Create a ZIP file: &lt;code&gt;zip -r function.zip index.js node_modules&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  4. Frontend Setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  4.1 Create React App
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Create a new Vite project: &lt;code&gt;npm create vite@latest client -- --template react&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Navigate to the project directory: &lt;code&gt;cd client&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Install dependencies: &lt;code&gt;npm install&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  4.2 API Service
&lt;/h3&gt;

&lt;p&gt;Create a file named &lt;code&gt;src/services/todoService.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios&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;API_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://your-api-gateway-url.execute-api.us-west-2.amazonaws.com/prod/todos&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;api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;baseURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;API_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;withCredentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getTodos&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="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;response&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;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createTodo&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;title&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;response&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;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&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="nx"&gt;title&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updateTodo&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;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updates&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;response&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;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/&lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;{id}`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updates&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;deleteTodo&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;id&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/&lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;{id}`&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;h3&gt;
  
  
  4.3 Main App Component
&lt;/h3&gt;

&lt;p&gt;Update &lt;code&gt;src/App.jsx&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getTodos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;createTodo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateTodo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;deleteTodo&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./services/todoService&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./App.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setTodos&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;newTodo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setNewTodo&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&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="nf"&gt;fetchTodos&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchTodos&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="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;fetchedTodos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getTodos&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;setTodos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fetchedTodos&lt;/span&gt;&lt;span class="p"&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;handleCreateTodo&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;e&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="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newTodo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&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;createdTodo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createTodo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newTodo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;setTodos&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;createdTodo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
      &lt;span class="nf"&gt;setNewTodo&lt;/span&gt;&lt;span class="p"&gt;(&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleUpdateTodo&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;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updates&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;updatedTodo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;updateTodo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updates&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setTodos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;updatedTodo&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&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;handleDeleteTodo&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;id&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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;deleteTodo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setTodos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_id&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;));&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"App"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Todo App&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt; &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleCreateTodo&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;newTodo&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setNewTodo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Add a new todo"&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Add Todo&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt;
              &lt;span class="na"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;handleUpdateTodo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&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;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;textDecoration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;line-through&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;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;handleDeleteTodo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Delete&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. AWS Configuration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  5.1 Lambda Function
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Create a new Lambda function in the AWS Console.&lt;/li&gt;
&lt;li&gt;Upload the ZIP file created in step 3.3.&lt;/li&gt;
&lt;li&gt;Set the handler to &lt;code&gt;index.handler&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add environment variable: &lt;code&gt;MONGODB_URI&lt;/code&gt; with your MongoDB connection string.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  5.2 API Gateway
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Create a new API in API Gateway.&lt;/li&gt;
&lt;li&gt;Create resources and methods for /todos and /todos/{id}.&lt;/li&gt;
&lt;li&gt;Integrate each method with your Lambda function.&lt;/li&gt;
&lt;li&gt;Enable CORS for each method.&lt;/li&gt;
&lt;li&gt;Deploy the API to a new stage (e.g., "prod").&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  5.3 S3 and CloudFront
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Create an S3 bucket for hosting the React app.&lt;/li&gt;
&lt;li&gt;Create a CloudFront distribution with the S3 bucket as the origin.&lt;/li&gt;
&lt;li&gt;Set up Origin Access Control (OAC) for secure access to the S3 bucket.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  6. Deployment
&lt;/h2&gt;

&lt;h3&gt;
  
  
  6.1 Backend Deployment
&lt;/h3&gt;

&lt;p&gt;Update the Lambda function code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zip &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;.zip index.js node_modules
aws lambda update-function-code &lt;span class="nt"&gt;--function-name&lt;/span&gt; YourFunctionName &lt;span class="nt"&gt;--zip-file&lt;/span&gt; fileb://function.zip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6.2 Frontend Deployment
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Build the React app: &lt;code&gt;npm run build&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Upload to S3:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   aws s3 &lt;span class="nb"&gt;sync &lt;/span&gt;build/ s3://your-bucket-name &lt;span class="nt"&gt;--delete&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Invalidate CloudFront cache:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   aws cloudfront create-invalidation &lt;span class="nt"&gt;--distribution-id&lt;/span&gt; YourDistributionID &lt;span class="nt"&gt;--paths&lt;/span&gt; &lt;span class="s2"&gt;"/*"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7. Troubleshooting
&lt;/h2&gt;

&lt;h3&gt;
  
  
  7.1 CORS Issues
&lt;/h3&gt;

&lt;p&gt;If encountering CORS errors:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ensure CORS is enabled in API Gateway for all methods.&lt;/li&gt;
&lt;li&gt;Verify CORS headers in the Lambda function response.&lt;/li&gt;
&lt;li&gt;Check that the &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; header matches your CloudFront domain.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  7.2 API Gateway 5XX Errors
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Check Lambda function logs in CloudWatch.&lt;/li&gt;
&lt;li&gt;Verify that the Lambda function has the correct permissions to access other AWS services.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  7.3 MongoDB Connection Issues
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Ensure the &lt;code&gt;MONGODB_URI&lt;/code&gt; environment variable is set correctly in Lambda.&lt;/li&gt;
&lt;li&gt;Verify that the Lambda function has network access to MongoDB Atlas (may require VPC configuration).&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  8. Maintenance and Updates
&lt;/h2&gt;

&lt;h3&gt;
  
  
  8.1 Updating the Backend
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Make changes to the Lambda function code.&lt;/li&gt;
&lt;li&gt;Redeploy using the steps in section 6.1.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  8.2 Updating the Frontend
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Make changes to the React application.&lt;/li&gt;
&lt;li&gt;Rebuild and redeploy using the steps in section 6.2.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  8.3 Monitoring
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Use CloudWatch to monitor Lambda function performance and errors.&lt;/li&gt;
&lt;li&gt;Set up CloudWatch Alarms for critical metrics.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  8.4 Scaling
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Adjust Lambda function memory and timeout settings as needed.&lt;/li&gt;
&lt;li&gt;Consider implementing caching at the API Gateway level for frequently accessed data.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This documentation provides a comprehensive guide for setting up, deploying, and maintaining your Todo application. Remember to keep your dependencies updated and regularly review AWS best practices for potential improvements to your architecture.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>node</category>
      <category>s3</category>
      <category>cloudfron</category>
    </item>
    <item>
      <title>Docker Hands-On Part 06</title>
      <dc:creator>Randika Madhushan Perera</dc:creator>
      <pubDate>Wed, 14 Feb 2024 12:51:54 +0000</pubDate>
      <link>https://dev.to/randiakm/docker-hands-on-part-06-2a2p</link>
      <guid>https://dev.to/randiakm/docker-hands-on-part-06-2a2p</guid>
      <description>&lt;h2&gt;
  
  
  06. Docker Container Networking
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The process of containerizing applications represents a significant leap forward in how we deploy and manage software. The Flask framework, popular for its simplicity and flexibility for web application development, is an excellent candidate for Dockerization. This transformative journey from a centralized server setup to a containerized deployment offers numerous advantages, including streamlined deployment processes, improved scalability, and enhanced isolation for development and production environments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Journey to Dockerize a Flask Application&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The task at hand involves moving a Flask application, aptly named "Notes App," into a Docker container. This application, designed for employees to store notes on current projects, will benefit from the portability and efficiency that containers provide.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step-by-Step Guide to Containerization&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;01. Initial Configuration:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Begin by writing the necessary configuration code, including a Dockerfile and .dockerignore file, to build a clean and efficient Docker image for the Notes App.&lt;/p&gt;

&lt;p&gt;Step 01: Create Dokcerignore file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ vim .dockerignore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;add below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Exclude files
.dockeringnore
Dockerfile
.gitignore
Pipfile.lock
migrations/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create &lt;code&gt;Dockerfile&lt;/code&gt; and add below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# version 01
FROM python:3
ENV PYBASE /pybase
ENV PYTHONUSERBASE $PYBASE
ENV PATH $PYABASE/bin:$PATH
#install pipenv
RUN pip install pipenv

WORKDIR /tmp
COPY Pipfile .
RUN pipenv lock
RUN PIP_USER=1 PIP_IGNORE_INSTALLED=1 pipenv install -d --system --ignore-pipfile

COPY . /app/notes
WORKDIR /app/notes
EXPOSE 80
CMD ["flask", "run", "--port=80", "--host=0.0.0.0"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Building the First Image:&lt;/p&gt;

&lt;p&gt;With the Dockerfile in place, build the initial image version of the Notes App. This step includes setting up the database within a container derived from the first image, ensuring that the application's data layer is ready for use.&lt;/p&gt;

&lt;p&gt;Step 02: Build the image and container&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker build -t notesapp:0.1 .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 03: Create and run a container for postgres:12.1-alpine&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker pull postgres:12.1-alpine

$ docker run -d --name notesdb postgres:12.1-alpine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 04: Create a network and attach it to the bridge network&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker network create -d bridge notes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 05: List the docker networks&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker network ls

NETWORK ID     NAME      DRIVER    SCOPE
df7f5f15c7ab   bridge    bridge    local
7405f25b96f6   host      host      local
ee4c71834f71   none      null      local
14219a8cf079   notes     bridge    local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 06: Run a container using the notesapp image and mount the migrations directory&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker run --rm -it --network notes -v /home/ec2-user/notes/migrations:/app/notes/migrations notesapp:0.1 bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 07:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# flask db migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running the Application:&lt;/p&gt;

&lt;p&gt;Deploy the Notes App container to verify its functionality. During this phase, monitoring the logs for any issues, such as the application running in debug mode, is crucial. Debug mode is not suitable for production due to potential security and performance implications.&lt;br&gt;
Enhancing for Production:&lt;/p&gt;

&lt;p&gt;Address the debug mode issue by switching the Flask application to run on a more robust WSGI (Web Server Gateway Interface) server, such as Gunicorn. This change involves updating the environment variables, modifying the pip file to include Gunicorn, and adjusting the Dockerfile to execute Gunicorn instead of Flask directly.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>aws</category>
      <category>docker</category>
    </item>
    <item>
      <title>Docker Hands-On Part 05</title>
      <dc:creator>Randika Madhushan Perera</dc:creator>
      <pubDate>Wed, 14 Feb 2024 12:51:28 +0000</pubDate>
      <link>https://dev.to/randiakm/docker-hands-on-part-05-18hh</link>
      <guid>https://dev.to/randiakm/docker-hands-on-part-05-18hh</guid>
      <description>&lt;h2&gt;
  
  
  05. Building Container Images Using Dockerfiles
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The evolution of container technology seeks to address and simplify the deployment process, making it more efficient and less prone to errors. Manual image creation, while possible, contradicts this objective by introducing unrepeatable processes fraught with potential mistakes. Dockerfiles represent Docker's solution to this challenge, enabling the automation of image creation through a process that is both reproducible and version-controllable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Dockerfile Advantage&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A Dockerfile is essentially a script composed of various commands, each instructing Docker how to build a specific image. This method allows developers to define their images as code, significantly reducing the manual labor involved in image creation and ensuring that the process can be easily repeated and integrated into continuous integration/continuous deployment (CI/CD) pipelines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Building an Image for a Web Server&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this tutorial, we'll demonstrate how to utilize a Dockerfile to build a container image designed to serve a company's website. The process will be divided into three key versions, each improving upon the last:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Version 1: Updating the Base Image&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Start by creating a Dockerfile that updates the base image using the package manager. While updating the base image is generally not required for every Dockerfile, it serves as an illustrative first step in this tutorial.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Version 2: Removing the Default Apache Welcome Page&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The second version of the Dockerfile will modify the image to remove the default Apache welcome page. This step is crucial for preparing the image to host custom web content.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Version 3: Adding Website Data to the Image&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The final version of the Dockerfile will incorporate the actual website data into the image. This ensures that the website is served directly from the container upon startup, providing a seamless deployment experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deploying the Final Image&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once the Dockerfile for version 3 is complete, the next step involves building the image and running a container from it. This process will demonstrate the web server in action, serving the company's website from the containerized environment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Getting Started&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To begin, create a Dockerfile in a directory dedicated to this project. The Dockerfile will evolve through each version, culminating in a container image that is ready for deployment. This method not only streamlines the development and deployment process but also aligns with best practices for managing application infrastructure as code.&lt;/p&gt;

&lt;p&gt;Step 01: Create a Docker file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cd content-widget-factory-inc

$ vim Dokcerfile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;add the below codes to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#base image httpd
FROM httpd:latest   
# Run the app update
RUN apt update -y &amp;amp;&amp;amp; apt upgrade -y &amp;amp;&amp;amp; apt autoremove -y &amp;amp;&amp;amp; apt clean &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 02: Build the image&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker build -t widgetfactory:0.1 .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can see&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker images

REPOSITORY              TAG       IMAGE ID       CREATED          SIZE
widgetfactory           0.1       b1f9112e68d5   22 seconds ago   180MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 03: Set variables to examine the image's size and layers&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ export showLayers='{{ range .RootFS.Layers }}{{ println . }}{{end}}'
$ export showSize='{{ .Size }}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 04: Show the widgetfactory image's size&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker inspect -f "$showSize" widgetfactory:0.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 05: We are going to change Dockerfile&lt;/p&gt;

&lt;p&gt;Add the below two lines &lt;/p&gt;

&lt;p&gt;&lt;code&gt;WORKDIR /usr/local/apache2/htdocs&lt;br&gt;
COPY ./web .&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#base image httpd
FROM httpd:latest   
# Run the app update
RUN apt update -y &amp;amp;&amp;amp; apt upgrade -y &amp;amp;&amp;amp; apt autoremove -y &amp;amp;&amp;amp; apt clean &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists*
WORKDIR /usr/local/apache2/htdocs
COPY ./web . 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker build -t widgetfactory:0.2 .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 06: Get the widgetfactory:0.2 container&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker run --rm -it widgetfactory:0.3 bash

$ ls -l
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 07: Run the container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker run -d --name web1 -p 80:80 widgetfactory:0.3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 08: Let's test&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ wget localhost

--2024-02-14 10:31:37--  http://localhost/
Resolving localhost (localhost)... 127.0.0.1
Connecting to localhost (localhost)|127.0.0.1|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3276 (3.2K) [text/html]
Saving to: ‘index.html’

index.html                                          100%[=================================================================================================================&amp;gt;]   3.20K  --.-KB/s    in 0s

2024-02-14 10:31:37 (376 MB/s) - ‘index.html’ saved [3276/3276]

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

&lt;/div&gt;



</description>
      <category>tutorial</category>
      <category>aws</category>
      <category>docker</category>
    </item>
    <item>
      <title>Docker Hands-On Part 04</title>
      <dc:creator>Randika Madhushan Perera</dc:creator>
      <pubDate>Fri, 09 Feb 2024 17:15:47 +0000</pubDate>
      <link>https://dev.to/randiakm/docker-hands-on-part-04-1224</link>
      <guid>https://dev.to/randiakm/docker-hands-on-part-04-1224</guid>
      <description>&lt;h2&gt;
  
  
  04. Storing Container Data In Docker Volumes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this lesson, you are going to learn how to store your container data in Docker Volumes. You can store config files, static shared files, or any stateful information that you need. &lt;/p&gt;

&lt;p&gt;Here we are going to create 3 docker volumes. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step-by-Step Guide Storing Container Data In Docker Volumes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Step 01: Run the &lt;code&gt;docker volume&lt;/code&gt; command to see if having existing docker volumes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker volume ls

DRIVER    VOLUME NAME
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 02: Now pull the image for Postgres image for setting up the docker volumes. Here I'm using Postgres 12.1. Postgres needs volumes in the background for the data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker pull postgres:12.1

$ docker run -d --name db1 postgres:12.1

$ docker run -d --name db2 postgres:12.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 03: Now run the docker volume command to see the volumes&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker volume ls

DRIVER    VOLUME NAME
local     1ae4ee6124f0bee423bec887931d9d80aec330a50b5e4edbaf4f151a19c2f23a
local     3dd9a005bb83fc892e2098237fa2bb3ad26407b82bb28096b64a327f26f4eb89
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 04: It's very difficult to identify the volumes that using above. So we can run the below command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker inspect db1 -f '{{ json .Mounts }}' | python -m json.tool

[
    {
        "Type": "volume",
        "Name": "3dd9a005bb83fc892e2098237fa2bb3ad26407b82bb28096b64a327f26f4eb89",
        "Source": "/var/lib/docker/volumes/3dd9a005bb83fc892e2098237fa2bb3ad26407b82bb28096b64a327f26f4eb89/_data",
        "Destination": "/var/lib/postgresql/data",
        "Driver": "local",
        "Mode": "",
        "RW": true,
        "Propagation": ""
    }
]

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Create the Docker Volumes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Step 01: We can create docker volumes using the &lt;code&gt;create&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker volume create website

DRIVER    VOLUME NAME
local     1ae4ee6124f0bee423bec887931d9d80aec330a50b5e4edbaf4f151a19c2f23a
local            e534041b91b8b520b79a9f42c4f97fa260cae5e25a11517ce2eed0f92faefad2
local     website

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

&lt;/div&gt;



&lt;p&gt;Step 02: Put data in the docker volumes. So we are going to put our web app codes under the &lt;em&gt;website&lt;/em&gt; volume&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$  sudo cp -r /home/ec2-user/content-widget-factory-inc/web/* /var/lib/docker/volumes/website/_data/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To see the files&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo ls -l /var/lib/docker/volumes/website/_data
total 16
drwxr-xr-x. 2 root root   76 Feb  9 16:51 img
-rw-r--r--. 1 root root 3276 Feb  9 16:51 index.html
-rw-r--r--. 1 root root 2910 Feb  9 16:51 quote.html
-rw-r--r--. 1 root root 2611 Feb  9 16:51 support.html
-rw-r--r--. 1 root root 2645 Feb  9 16:51 widgets.html

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Remove Unused Docker Volumes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Run the &lt;code&gt;docker volume prune&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker volume prune

WARNING! This will remove anonymous local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Volumes:
1ae4ee6124f0bee423bec887931d9d80aec330a50b5e4edbaf4f151a19c2f23a
b61fc8243670de085a3fb120fceec864893ec097838e8be67c05b2e47daaef99
107c5e2f43fb50271133c7df2868716f2f4080e65dcc5cf2367581be6425149e

Total reclaimed space: 0B

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Backup and Restore data from Docker Volumes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To do this we need to switch to the root.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# docker ps -a
CONTAINER ID   IMAGE           COMMAND                  CREATED        STATUS        PORTS                                   NAMES
77fc2b4639f4   postgres:12.1   "docker-entrypoint.s…"   4 hours ago    Up 4 hours    5432/tcp                                db2
dfa30582e464   postgres:12.1   "docker-entrypoint.s…"   4 hours ago    Up 4 hours    5432/tcp                                db1
53aace921e70   httpd:latest    "httpd-foreground"       12 hours ago   Up 12 hours   0.0.0.0:8080-&amp;gt;80/tcp, :::8080-&amp;gt;80/tcp   httpd


# docker volume ls
DRIVER    VOLUME NAME
local     3dd9a005bb83fc892e2098237fa2bb3ad26407b82bb28096b64a327f26f4eb89
local     e534041b91b8b520b79a9f42c4f97fa260cae5e25a11517ce2eed0f92faefad2
local     website

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

&lt;/div&gt;



&lt;p&gt;We need to inspect the volume.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# docker volume inspect website
[
    {
        "CreatedAt": "2024-02-09T16:48:21Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/website/_data",
        "Name": "website",
        "Options": null,
        "Scope": "local"
    }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get the backup we need to follow the below instructions. We are storing the backup under/tmp/ dir.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# tar czf /tmp/website_$(date +%Y-%m-%d-%H%M).tgz -C /var/lib/docker/volumes/website/_data .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ls -l /tmp/website_2024-02-09-1708.tgz
-rw-r--r--. 1 root root 11385 Feb  9 17:08 /tmp/website_2024-02-09-1708.tgz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we see how we are doing this using non-privileged users.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker run -it --rm -v website:/website -v /tmp:/backup bash tar czf /backup/website_$(date +%Y-%m-%d-%H%M).tgz -C /website .

$ ls -l /tmp/website_*
-rw-r--r--. 1 root root 11385 Feb  9 17:08 /tmp/website_2024-02-09-1708.tgz
-rw-r--r--. 1 root root 11375 Feb  9 17:13 /tmp/website_2024-02-09-1713.tgz

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

&lt;/div&gt;



</description>
      <category>tutorial</category>
      <category>aws</category>
      <category>docker</category>
    </item>
    <item>
      <title>Docker Hands-On Part 03</title>
      <dc:creator>Randika Madhushan Perera</dc:creator>
      <pubDate>Fri, 09 Feb 2024 09:17:31 +0000</pubDate>
      <link>https://dev.to/randiakm/docker-hands-on-part-03-4mf8</link>
      <guid>https://dev.to/randiakm/docker-hands-on-part-03-4mf8</guid>
      <description>&lt;h2&gt;
  
  
  03. Handcrafting a Container Image
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This approach to creating a container image, emphasizes the practicality of incorporating data directly into the image rather than manually mounting it each time a container is started. This method is particularly useful for web deployment, where efficiency and customization are key. The process outlined involves starting with a pre-built HTTPD image and modifying it to suit specific needs. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step-by-Step Guide to Creating a Handcrafted Container Image&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;01. Selecting a Base Image:&lt;/strong&gt; The journey begins with selecting HTTPD as the base image, a popular choice for serving web content.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;02. Adding Tools and Data:&lt;/strong&gt; To customize the container, tools are added to fetch website data from a repository, such as GitHub. This step ensures that the necessary content is directly embedded within the container.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;03. Creating the Initial Image:&lt;/strong&gt; After customizing the template container with the website's data, an image is created from this state, labeled Widget Factory v1.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;04. Optimizing the Image:&lt;/strong&gt; Inspection of the initial image reveals it to be larger than necessary due to residual installation artifacts. By removing these, a cleaner and more efficient image, Web App v2, is produced.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;05. Deployment and Testing:&lt;/strong&gt; Multiple containers are spawned from the optimized v2 image to test and view the final product in action.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Process Visualized&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The creation process visualizes the transition from a generic HTTPD latest version image to a specialized Widget Factory image. The initial modifications result in the v1 image, which is further refined to create the optimized v2 image. This final version is then used to run multiple containers, showcasing the website deployment.&lt;/p&gt;

&lt;p&gt;Step 01: Create another container called "webtemplate" using httpd.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker run --name webtemplate -d httpd:latest

$ docker ps -a
CONTAINER ID   IMAGE          COMMAND              CREATED         STATUS         PORTS                                   NAMES
4dadb7c6ca70   httpd:latest   "httpd-foreground"   5 seconds ago   Up 4 seconds   80/tcp                                  webtemplate

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

&lt;/div&gt;



&lt;p&gt;Step 02: Get an internal terminal of the webtemplate container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker exec -it webtemplate bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 03: Update the container and install git.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# apt update &amp;amp;&amp;amp; apt install -y git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 04: Clone the repo from the GitHub. &lt;/p&gt;

&lt;p&gt;Repo Link: &lt;a href="https://github.com/RandiakM/content-widget-factory-inc.git" rel="noopener noreferrer"&gt;https://github.com/RandiakM/content-widget-factory-inc.git&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# git clone https://github.com/RandiakM/content-widget-factory-inc.git /tmp/widget-factory-inc

# ls -l /tmp/widget-factory-inc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 05: Now we need to set up the htdocs folder. Remove the default apache page and copy our web pages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root@4dadb7c6ca70:/usr/local/apache2# pwd
/usr/local/apache2

# rm -rf htdocs/index.html

# cp -r /tmp/widget-factory-inc/web/* htdocs

# ls -l htdocs 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 06: Create an image from the container, we need the container ID.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker ps -a
CONTAINER ID   IMAGE          COMMAND              CREATED             STATUS             PORTS                                   NAMES
4dadb7c6ca70   httpd:latest   "httpd-foreground"   About an hour ago   Up About an hour   80/tcp                                  webtemplate

$ docker commit 4dadb7c6ca70 example/widgetfactory:v1

$ docker images
[ec2-user@ip-172-16-1-10 ~]$ docker images
REPOSITORY              TAG       IMAGE ID       CREATED          SIZE
example/widgetfactory   v1        1676623db0fc   11 seconds ago   277MB
httpd                   latest    59bcd61b45fd   3 weeks ago      167MB
hello-world             latest    d2c94e258dcb   9 months ago     13.3kB

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

&lt;/div&gt;



&lt;p&gt;You can see our &lt;code&gt;example/widgetfactory&lt;/code&gt; size is large. All this coming from the extra build tools. We need to clean this up. &lt;/p&gt;

&lt;p&gt;Step 07: Go to the inside of the container, and need to remove git, web app codes, and remove the cache.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker exec -it webtemplate bash

# rm -rf /tmp/widget-factory-inc

# apt remove git -y &amp;amp;&amp;amp; apt autoremove -y &amp;amp;&amp;amp; apt clean

# exit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 08: Now we need to run &lt;code&gt;docker commit&lt;/code&gt; again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker commit 4dadb7c6ca70 example/widgetfactory:v2

$ docker images
REPOSITORY              TAG       IMAGE ID       CREATED         SIZE
example/widgetfactory   v2        01e2bd60f515   7 seconds ago   187MB
example/widgetfactory   v1        1676623db0fc   7 minutes ago   277MB
httpd                   latest    59bcd61b45fd   3 weeks ago     167MB

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

&lt;/div&gt;



&lt;p&gt;Step 09: Remove v1 image and run the v2. Stop the webtemplate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker rmi example/widgetfactory:v1

$ docker run -d --name web1 -p 8081:80  example/widgetfactory:v2

$ docker ps -a
CONTAINER ID   IMAGE                      COMMAND              CREATED             STATUS             PORTS                                   NAMES
adaf110c7088   example/widgetfactory:v2   "httpd-foreground"   4 seconds ago       Up 3 seconds       0.0.0.0:8081-&amp;gt;80/tcp, :::8081-&amp;gt;80/tcp   web1
4dadb7c6ca70   httpd:latest               "httpd-foreground"   About an hour ago   Up About an hour   80/tcp                                  webtemplate
53aace921e70   httpd:latest               "httpd-foreground"   4 hours ago         Up 4 hours         0.0.0.0:8080-&amp;gt;80/tcp, :::8080-&amp;gt;80/tcp   httpd


$ docker stop webtemplate

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

&lt;/div&gt;



&lt;p&gt;Step 10: Now in your browser navigate to the public_ip:8081&lt;/p&gt;

</description>
      <category>aws</category>
      <category>docker</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Docker Hands-On Part 02</title>
      <dc:creator>Randika Madhushan Perera</dc:creator>
      <pubDate>Fri, 09 Feb 2024 03:25:39 +0000</pubDate>
      <link>https://dev.to/randiakm/docker-hands-on-part-02-34cj</link>
      <guid>https://dev.to/randiakm/docker-hands-on-part-02-34cj</guid>
      <description>&lt;h2&gt;
  
  
  02. Working With Prebuilt Docker Images
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Overview&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's say you have been assigned a task to migrate a website from a server to a container. So how do we get a container? The easy way is to create a container from a prebuilt image. Since we are hosting a website we will need a web server. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This lab has 5 goals;&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Explore Docker Hub: We have to find the web server images we want to try. &lt;/li&gt;
&lt;li&gt;Get and View httpd: Retrieve the httpd image from Docker Hub, run a container from the image, and view the results. &lt;/li&gt;
&lt;li&gt;Run the Website in httpd: Get the website content, add it to an httpd container, and view the webpage. &lt;/li&gt;
&lt;li&gt;Get and View Nginx: Retrieve the nginx image from Docker Hub, run a container from the image, and view the results. &lt;/li&gt;
&lt;li&gt;Run the website in Nginx: Add the website content to an nginx container and view the webpage. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When we hit the server from our browser, the web page will load. We want that same thing to happen with the containers. We'll load the website into an httpd container and then when we hit it, it will get back to the same website. Lastly, we'll host the site using nginx just like we did with httpd. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Explore Docker Hub&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Navigate to the Docker Hub and find the httpd container (latest). &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fpq0ixkh1j9hrjol58cr6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fpq0ixkh1j9hrjol58cr6.png" alt="httpd-container" width="800" height="233"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step 01: Verify the docker service is running by using the below command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 02: We can start by pulling the httpd docker from the Docker Hub.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker pull httpd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 03: To see the docker images run the below command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker images
REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
httpd         latest    59bcd61b45fd   2 weeks ago    167MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 04: Now we need to start our container&lt;/p&gt;

&lt;p&gt;the port will be 8080 on the server and port 80 will be connected in to the container. (-p 8080:80) &lt;/p&gt;

&lt;p&gt;-d --&amp;gt; detach mode&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker run --name httpd -p 8080:80 -d httpd:latest
016b3196078f73a0ea062024b4b6b82430a81aad1b02fe8329fa78997931fc

$ docker ps -a
CONTAINER ID   IMAGE          COMMAND              CREATED          STATUS          PORTS                                   NAMES
016b3196078f   httpd:latest   "httpd-foreground"   44 seconds ago   Up 43 seconds   0.0.0.0:8080-&amp;gt;80/tcp, :::8080-&amp;gt;80/tcp   httpd

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

&lt;/div&gt;



&lt;p&gt;Step 05: Now we can test it if the httpd is running using a web browser. &lt;/p&gt;

&lt;p&gt;Enter your server's public IP in the web browser. You can see it. &lt;/p&gt;

&lt;p&gt;Step 06: Pulling the content. &lt;/p&gt;

&lt;p&gt;GitHub Repo: &lt;a href="https://github.com/RandiakM/content-widget-factory-inc.git" rel="noopener noreferrer"&gt;Link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We are using the git clone command to clone the repo. If you haven't installed git on your server, you need to &lt;a href="https://git-scm.com/download/linux" rel="noopener noreferrer"&gt;install&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git clone https://github.com/RandiakM/content-widget-factory-inc.git

$ cd content-widget-factory-inc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 07: Now we need to mount this web app with our httpd docker. First, we need to stop the httpd docker.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker stop httpd
httpd

$ docker ps -a
CONTAINER ID   IMAGE          COMMAND              CREATED      STATUS                     PORTS     NAMES
016b3196078f   httpd:latest   "httpd-foreground"   2 days ago   Exited (0) 4 seconds ago             httpd

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

&lt;/div&gt;



&lt;p&gt;So if we are trying to mount this with the same name it will give an error, to avoid this we can remove the container for httpd.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker rm httpd
httpd

[ec2-user@ip-172-16-1-10 web]$ docker ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

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

&lt;/div&gt;



&lt;p&gt;Step 08: Mount the web with the container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker run --name httpd -p 8080:80 -v /home/ec2-user/content-widget-factory-inc/web:/usr/local/apache2/htdocs:ro -d httpd:latest
f4eca276afa82dcc50424ad4a3d0ebcb344c946f6797aebfaaada4c2b432e54f


$ docker ps -a
CONTAINER ID   IMAGE          COMMAND              CREATED          STATUS          PORTS                                   NAMES
f4eca276afa8   httpd:latest   "httpd-foreground"   12 seconds ago   Up 11 seconds   0.0.0.0:8080-&amp;gt;80/tcp, :::8080-&amp;gt;80/tcp   httpd

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

&lt;/div&gt;



&lt;p&gt;Step 09: Now you can navigate "&lt;a href="http://public_ip:8080/" rel="noopener noreferrer"&gt;http://public_ip:8080/&lt;/a&gt;" to see the web app. &lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>docker</category>
      <category>containers</category>
    </item>
    <item>
      <title>Docker Hands-On Part 01</title>
      <dc:creator>Randika Madhushan Perera</dc:creator>
      <pubDate>Sun, 04 Feb 2024 09:42:29 +0000</pubDate>
      <link>https://dev.to/randiakm/docker-hands-on-part-01-2laj</link>
      <guid>https://dev.to/randiakm/docker-hands-on-part-01-2laj</guid>
      <description>&lt;h2&gt;
  
  
  01. Initializing the Docker Environment
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Installing Docker CE&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Installing Required Packages:&lt;/strong&gt; If you are using Essential packages for Docker CE in CentOS, such as &lt;code&gt;utils&lt;/code&gt;, &lt;code&gt;device-mapper-persistent-data&lt;/code&gt;, and &lt;code&gt;lvm2&lt;/code&gt;, are installed using the &lt;code&gt;yum&lt;/code&gt; package manager.&lt;/p&gt;

&lt;p&gt;I'm using the Linux EC2 2023 server. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To install Docker on Amazon Linux 2 or Amazon Linux 2023&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;1.Update the installed packages and package cache on your instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo yum update -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2.Install the most recent Docker Community Edition package.&lt;/p&gt;

&lt;p&gt;For Amazon Linux 2, run the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo amazon-linux-extras install docker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Amazon Linux 2023, run the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo yum install -y docker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3.Start and enable the Docker service&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ systemctl enable --now docker.service
$ systemctl ststus docker.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the &lt;em&gt;ec2-user&lt;/em&gt; to the docker group so that you can run Docker commands without using sudo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo usermod -a -G docker ec2-user
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pick up the new docker group permissions by logging out and logging back in again. To do this, close your current SSH terminal window and reconnect to your instance in a new one. Your new SSH session should have the appropriate docker group permissions.&lt;/p&gt;

&lt;p&gt;Verify that the ec2-user can run Docker commands without using sudo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker ps -a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>tutorial</category>
      <category>docker</category>
      <category>containers</category>
    </item>
    <item>
      <title>Learning Docker - Storage Driver</title>
      <dc:creator>Randika Madhushan Perera</dc:creator>
      <pubDate>Sun, 04 Feb 2024 08:40:31 +0000</pubDate>
      <link>https://dev.to/randiakm/learning-docker-storage-driver-aj6</link>
      <guid>https://dev.to/randiakm/learning-docker-storage-driver-aj6</guid>
      <description>&lt;h2&gt;
  
  
  03. Selecting a Storage Driver
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Overview&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this lesson, we delve into the concept of storage drivers within Docker, a pivotal component in managing the temporary internal storage of a container's writable layer. Docker's storage drivers facilitate a pluggable framework that allows for diverse management strategies of the container's internal storage, especially when the container's software writes data to disk without using mounted volumes or external storage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Role of Storage Drivers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Pluggable Framework:&lt;/strong&gt;&lt;/em&gt; Docker employs a pluggable framework for its storage drivers, offering flexibility in how container storage is managed. This adaptability is crucial for supporting multiple operating systems and environments, as certain storage methods are only viable in specific settings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Selection Criteria:&lt;/em&gt;&lt;/strong&gt; The choice of a storage driver depends on the operating system, environment, and specific use cases. Factors such as performance efficiency for read/write operations and compatibility with the underlying OS influence this decision.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Storage Drivers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Overlay2:&lt;/em&gt;&lt;/strong&gt; Overlay2 is a file-based storage driver and is the default option for both Ubuntu and CentOS (version 8 and newer). It is efficient for most general use cases, particularly where reading operations predominate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Devicemapper:&lt;/em&gt;&lt;/strong&gt; In contrast, Devicemapper offers block storage and is the default for CentOS 7 and earlier versions. It tends to perform better in scenarios with heavy write operations to the container layers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Managing Storage Drivers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Checking the Current Driver:&lt;/em&gt;&lt;/strong&gt; The docker info command can be used to identify the current storage driver in use. For example, CentOS 7 defaults to Devicemapper.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Changing Storage Drivers:&lt;/em&gt;&lt;/strong&gt; Users can override the default storage driver by either passing a flag to the Docker daemon or by specifying the desired driver in the daemon.json configuration file. The latter method is recommended for its standardization across different environments.&lt;/p&gt;

&lt;p&gt;Run the below command to see the docker-storage option&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker info&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker info
Client:
 Version:    24.0.5
 Context:    default
 Debug Mode: false
 Plugins:
  buildx: Docker Buildx (Docker Inc.)
    Version:  v0.0.0+unknown
    Path:     /usr/libexec/docker/cli-plugins/docker-buildx

Server:
 Containers: 1
  Running: 0
  Paused: 0
  Stopped: 1
 Images: 1
 Server Version: 24.0.5
Storage Driver: overlay2
  Backing Filesystem: xfs

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

&lt;/div&gt;



&lt;p&gt;In my case, I have Storage Driver as &lt;code&gt;overlay2&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Practical Application&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I used the AWS Ec2 Linux 2023 server, showing how to check the current storage driver and switch to a different one if necessary. &lt;br&gt;
The process involves editing the Docker daemon's configuration file (daemon.json) to explicitly set the storage driver to &lt;code&gt;devicemapper&lt;/code&gt; or &lt;code&gt;overlay2&lt;/code&gt; highlighting the standardized approach for modifying Docker daemon settings.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ vim /etc/docker/daemon.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;daemon.json&lt;/code&gt; file you need to put below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "storage-driver": "overlay2"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ systemctl restart docker.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Understanding and effectively managing Docker's storage drivers is essential for optimizing container performance and ensuring compatibility with various environments. This lesson provides a foundational knowledge of Docker storage drivers, setting the stage for more advanced container management and operation practices in subsequent lessons.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>docker</category>
      <category>containers</category>
    </item>
  </channel>
</rss>
