<?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: kkkensuke</title>
    <description>The latest articles on DEV Community by kkkensuke (@kkkensuke).</description>
    <link>https://dev.to/kkkensuke</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%2F1013088%2F4a55f13f-05d9-4f19-a433-b1e32ef1a012.png</url>
      <title>DEV Community: kkkensuke</title>
      <link>https://dev.to/kkkensuke</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kkkensuke"/>
    <language>en</language>
    <item>
      <title>Automating EC2 Patching with AWS Patch Manager</title>
      <dc:creator>kkkensuke</dc:creator>
      <pubDate>Sun, 22 Sep 2024 06:50:40 +0000</pubDate>
      <link>https://dev.to/kkkensuke/automating-ec2-patching-with-aws-patch-manager-a7h</link>
      <guid>https://dev.to/kkkensuke/automating-ec2-patching-with-aws-patch-manager-a7h</guid>
      <description>&lt;p&gt;As a cloud engineer, managing EC2 patching is critical for security and performance. I’ve developed a solution to automate this process using AWS Patch Manager, encapsulated in this repository: &lt;a href="https://github.com/kkkensuke/patch-manager-control-public" rel="noopener noreferrer"&gt;Patch Manager Control&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Components:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;IAM Roles &amp;amp; Policies&lt;/strong&gt;: These govern permissions for Patch Manager and Maintenance Window tasks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SNS Notifications&lt;/strong&gt;: Used to send patching status updates.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Patch Baseline &amp;amp; Groups&lt;/strong&gt;: Define the patching rules for Amazon Linux 2 instances.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Maintenance Windows&lt;/strong&gt;: Scheduled tasks for patch scans and installations using cron expressions, ensuring regular updates without manual intervention.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How It Works:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Patch Baseline&lt;/strong&gt;: This defines approved patches, installation rules, and compliance levels.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintenance Window&lt;/strong&gt;: The window during which patches are applied, configurable via &lt;code&gt;variables.tf&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tag-Based Targeting&lt;/strong&gt;: Instances tagged with a specific &lt;code&gt;PatchGroup&lt;/code&gt; are automatically included for patching.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The repository integrates seamlessly into AWS environments using Terraform for infrastructure as code. Simply set up the required variables, apply Terraform, and let AWS take over the heavy lifting of patch management. It includes two primary tasks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Patch Scanning&lt;/strong&gt;: Periodically checks instances for missing updates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Patch Installation&lt;/strong&gt;: Installs updates based on the predefined schedule.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Repository Structure:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;main.tf&lt;/code&gt;&lt;/strong&gt;: Core Terraform configurations for AWS Patch Manager.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;variables.tf&lt;/code&gt;&lt;/strong&gt;: Parameterizes the maintenance window schedule and other key details.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;outputs.tf&lt;/code&gt;&lt;/strong&gt;: Displays key outputs such as the SNS topic and maintenance window IDs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting Up:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Clone the repository.&lt;/li&gt;
&lt;li&gt;Customize the &lt;code&gt;variables.tf&lt;/code&gt; file to match your EC2 patching needs (e.g., cron schedule, tags).&lt;/li&gt;
&lt;li&gt;Deploy the infrastructure using Terraform.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform init
terraform apply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once deployed, the setup will continuously manage patching without manual oversight, ensuring your instances are always up-to-date with minimal intervention.&lt;/p&gt;

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

&lt;p&gt;This repository simplifies EC2 patching automation, leveraging AWS native tools and infrastructure-as-code practices. If you’re looking for a robust solution for patch management, this project is designed to save time and reduce operational risk.&lt;/p&gt;

&lt;p&gt;Check out the repository here to get started with automating EC2 patching today!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>terraform</category>
    </item>
    <item>
      <title>Hosting a Static Site with CloudFront and S3 Using GitHub Actions</title>
      <dc:creator>kkkensuke</dc:creator>
      <pubDate>Mon, 16 Sep 2024 08:48:14 +0000</pubDate>
      <link>https://dev.to/kkkensuke/hosting-a-static-site-with-cloudfront-and-s3-using-github-actions-35bb</link>
      <guid>https://dev.to/kkkensuke/hosting-a-static-site-with-cloudfront-and-s3-using-github-actions-35bb</guid>
      <description>&lt;p&gt;Recently, I worked on a project to host a React application statically using S3 and CloudFront. In this blog, I will explain the architecture and the setup of the CICD pipeline.&lt;/p&gt;

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

&lt;p&gt;The architecture I implemented consists of the following components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;S3 Bucket&lt;/strong&gt;: Hosts the static files of the React application. S3 is ideal for serverless static site hosting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CloudFront&lt;/strong&gt;: A CDN (Content Delivery Network) that delivers content from S3 with high performance. It uses edge locations around the world to serve content closer to users, improving performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Actions&lt;/strong&gt;: Used to build and deploy the React application, automating the CICD pipeline.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting Up the CICD Pipeline
&lt;/h2&gt;

&lt;p&gt;The CICD pipeline is built using GitHub Actions. Whenever code is pushed to the repository, the following processes are executed:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Build React App&lt;/strong&gt;: Build the application using the &lt;code&gt;npm run build&lt;/code&gt; command to generate the static files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy to S3&lt;/strong&gt;: Upload the built files to S3.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Invalidate CloudFront Cache&lt;/strong&gt;: Invalidate the CloudFront cache to ensure the new version of the content is served.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  GitHub Actions Workflow File
&lt;/h3&gt;

&lt;p&gt;Here is a snippet of the GitHub Actions workflow file used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload files to S3&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;

&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;MY_AWS_REGION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;YOUR&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;AWS&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;REGION&amp;gt;'&lt;/span&gt;
  &lt;span class="na"&gt;AWS_ROLENAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;YOUR&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;AWS&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ROLE&amp;gt;'&lt;/span&gt;
  &lt;span class="na"&gt;AWS_S3_BUCKET&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;YOUR&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;S3&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;BUCKET&amp;gt;'&lt;/span&gt;
  &lt;span class="na"&gt;SOURCE_DIR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./build'&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;id-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
      &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@master&lt;/span&gt;

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

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

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build project&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Configure AWS credentials with IAM Role&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/configure-aws-credentials@v4&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;role-to-assume&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/${{ env.AWS_ROLENAME }}&lt;/span&gt;
        &lt;span class="na"&gt;aws-region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.MY_AWS_REGION }}&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Sync files to S3&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;aws s3 sync ${{ env.SOURCE_DIR }} s3://${{ env.AWS_S3_BUCKET }}/ --delete --exclude '.*git*'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Invalidate CloudFront Cache&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;aws cloudfront create-invalidation \&lt;/span&gt;
            &lt;span class="s"&gt;--distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} \&lt;/span&gt;
            &lt;span class="s"&gt;--paths "/*"&lt;/span&gt;


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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configuring S3 and CloudFront
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Creating an S3 Bucket&lt;/strong&gt;: Create a bucket and enable static website hosting. Configure the bucket to be accessible only through CloudFront for security.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Setting Up CloudFront&lt;/strong&gt;: Specify the S3 bucket as the origin and configure custom domains and SSL certificates as needed.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;With this setup, you can host a React application on S3 and CloudFront, providing fast and secure static site hosting. Additionally, the CICD pipeline with GitHub Actions automates the build and deployment process.&lt;/p&gt;

&lt;p&gt;For detailed code and configuration, check out the GitHub repository. &lt;a href="https://github.com/kkkensuke/staticsite-s3-cloudfront-githubactions-public" rel="noopener noreferrer"&gt;GitHub Repository Here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope this blog helps you with your projects. If you have any questions or feedback, feel free to leave a comment!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>AWS CDK with Automate Testing and TDD</title>
      <dc:creator>kkkensuke</dc:creator>
      <pubDate>Tue, 14 Feb 2023 05:48:33 +0000</pubDate>
      <link>https://dev.to/kkkensuke/aws-cdk-with-automate-testing-and-tdd-1mf</link>
      <guid>https://dev.to/kkkensuke/aws-cdk-with-automate-testing-and-tdd-1mf</guid>
      <description>&lt;p&gt;This post is third post after &lt;a href="https://dev.to/kkkensuke/aws-cdk-for-lambda-and-dynamodb-1bn9"&gt;this(Part2)&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Environment
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;AWS Cloud9&lt;/li&gt;
&lt;li&gt;CDK Version : 2.63.2&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What we do
&lt;/h2&gt;

&lt;p&gt;This time, we will perform the Fine-Grained Assertions test (Assertion Test) as described in the official &lt;a href="https://docs.aws.amazon.com/cdk/v2/guide/testing.html#testing_fine_grained" rel="noopener noreferrer"&gt;AWS documentation&lt;/a&gt;.&lt;br&gt;
In this test script, we will mainly use the hasResourceProperties function. This helper function is used when creating a resource in CDK to check "whether the resource has been created" and "the property values set for the resource.&lt;/p&gt;
&lt;h2&gt;
  
  
  Assertion Tests
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Create a test that the DynamoDB table has been created
&lt;/h3&gt;

&lt;p&gt;First, delete the unnecessary test/cdk-workshop.test.ts file. Then create the file test/hitcounter.test.ts and write the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Template, Capture } from 'aws-cdk-lib/assertions';
import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { HitCounter } from '../lib/hitcounter';

test('DynamoDB Table Created', () =&amp;gt; {
  const stack = new cdk.Stack();

  // WHEN
  new HitCounter(stack, 'MyTestConstruct', {
    downstream: new lambda.Function(stack, 'TestFunction', {
      runtime: lambda.Runtime.NODEJS_14_X,
      handler: 'hello.handler',
      code: lambda.Code.fromAsset('lambda')
    })
  });

  // THEN
  const template = Template.fromStack(stack);
  template.resourceCountIs("AWS::DynamoDB::Table", 1);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This test simply tests that the stack contains a DynamoDB table.&lt;br&gt;
Run the test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm run test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following results will be displayed&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm run test

&amp;gt; cdk-workshop@0.1.0 test
&amp;gt; jest

 PASS  test/hitcounter.test.ts (12.242 s)
  ✓ DynamoDB Table Created (177 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        12.439 s
Ran all test suites.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create a test that Lambda Function has been created
&lt;/h3&gt;

&lt;p&gt;Next, we will add a test case for the Lambda function. This time, in addition to test the creation of the Lambda function, we will also test the values of two environment variables (DOWNSTREAM_FUNCTION_NAME and HITS_TABLE_NAME). You specified these two environment variables when creating the Lambda function in Part 2.&lt;br&gt;
At this point, we do not know which values will be set for these two environment variables (these values were determined at the time of deployment), so we set dummy values for them. Therefore, the first test will fail, but the actual values of the environment variables are output in the failure log, so we will use those values later.&lt;br&gt;
Add a new test case as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test('Lambda Has Environment Variables', () =&amp;gt; {
  const stack = new cdk.Stack();

  // WHEN
  new HitCounter(stack, 'MyTestConstruct', {
    downstream: new lambda.Function(stack, 'TestFunctioin', {
      runtime: lambda.Runtime.NODEJS_14_X,
      handler: 'hello.handler',
      code: lambda.Code.fromAsset('lambda')
    })
  });

  // THEN
  const template = Template.fromStack(stack);
  const envCapture = new Capture();
  template.hasResourceProperties("AWS::Lambda::Function", {
    Environment: envCapture,
  });

  expect(envCapture.asObject()).toEqual(
    {
      Variables: {
        DOWNSTREAM_FUNCTION_NAME: {
          Ref: "TestFunctionXXXX",
        },
        HITS_TABLE_NAME: {
          Ref: "MyTestConstructHitsXXXX",
        }
      },
    }
  );
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After saving the file, run the test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm run test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One error is included in the test results as follows. The error contains the value of an environment variable that should be specified, so we will use this one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm run test

&amp;gt; cdk-workshop@0.1.0 test
&amp;gt; jest

 FAIL  test/hitcounter.test.ts (13.577 s)
  ✓ DynamoDB Table Created (198 ms)
  ✕ Lambda Has Environment Variables (99 ms)

  ● Lambda Has Environment Variables

    expect(received).toEqual(expected) // deep equality

    - Expected  - 2
    + Received  + 2

      Object {
        "Variables": Object {
          "DOWNSTREAM_FUNCTION_NAME": Object {
    -       "Ref": "TestFunctionXXXX",
    +       "Ref": "TestFunctioin03257049",
          },
          "HITS_TABLE_NAME": Object {
    -       "Ref": "MyTestConstructHitsXXXX",
    +       "Ref": "MyTestConstructHits24A357F0",
          },
        },
      }

      41 |   });
      42 |   
    &amp;gt; 43 |   expect(envCapture.asObject()).toEqual(
         |                                 ^
      44 |     {
      45 |       Variables: {
      46 |         DOWNSTREAM_FUNCTION_NAME: {

      at Object.&amp;lt;anonymous&amp;gt; (test/hitcounter.test.ts:43:33)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 passed, 2 total
Snapshots:   0 total
Time:        13.766 s
Ran all test suites.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now rewrite the contents of the test case using the values displayed in the above error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
expect(envCapture.asObject()).toEqual(
    {
      Variables: {
        DOWNSTREAM_FUNCTION_NAME: {
          Ref: "UPDATE Value from error log",
        },
        HITS_TABLE_NAME: {
          Ref: "UPDATE Value from error log",
        }
      },
    }
  );
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I ran the test again, and this time it worked!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; $ npm run test

&amp;gt; cdk-workshop@0.1.0 test
&amp;gt; jest

 PASS  test/hitcounter.test.ts (12.738 s)
  ✓ DynamoDB Table Created (150 ms)
  ✓ Lambda Has Environment Variables (94 ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        12.942 s, estimated 14 s
Ran all test suites.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  TDD (Test Driven Development）
&lt;/h3&gt;

&lt;p&gt;It is also possible to use the TDD methodology when creating a stack in CDK. As a simple example, suppose we have a new requirement to encrypt an existing DynamoDB table.&lt;br&gt;
The TDD approach would first reflect this requirement in a test script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test('DynamoDB Table Created With Encryption', () =&amp;gt; {
  const stack = new cdk.Stack();

  // WHEN
  new HitCounter(stack, 'MyTestConstruct', {
    downstream: new lambda.Function(stack, 'TestFunction', {
      runtime: lambda.Runtime.NODEJS_14_X,
      handler: 'hello.handler',
      code: lambda.Code.fromAsset('lambda')
    })
  });

  // THEN
  const template = Template.fromStack(stack);
  template.hasResourceProperties("AWS::DynamoDB::Table", {
    SSESpecification: {
      SSEEnabled: true
    }
  });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When I run the test, I think it will be an error. This is to be expected since we did not include the encryption setting in the constructor.&lt;br&gt;
So let's update the constructor to state that it will be encrypted for the DynamoDB table.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
 constructor(scope: Construct, id: string, props: HitCounterProps) {
    super(scope, id);

    const table = new dynamodb.Table(this, 'Hits', {
      partitionKey: { name: 'path', type: dynamodb.AttributeType.STRING },
      encryption: dynamodb.TableEncryption.AWS_MANAGED
    });
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the test again and see if it succeeds this time.&lt;br&gt;
So this is how CDK could be used to approach TDD!&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;What do you think? I think there are many projects where visual checks are done on the console, but with the CDK, we can test whether the AWS services are being built as expected, and the DevOps cycle will be faster. &lt;/p&gt;

&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://cdkworkshop.com/20-typescript/70-advanced-topics/100-construct-testing.html" rel="noopener noreferrer"&gt;https://cdkworkshop.com/20-typescript/70-advanced-topics/100-construct-testing.html&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>awscdk</category>
      <category>testing</category>
      <category>tdd</category>
    </item>
    <item>
      <title>AWS CDK for Lambda and DynamoDB</title>
      <dc:creator>kkkensuke</dc:creator>
      <pubDate>Mon, 13 Feb 2023 07:04:19 +0000</pubDate>
      <link>https://dev.to/kkkensuke/aws-cdk-for-lambda-and-dynamodb-1bn9</link>
      <guid>https://dev.to/kkkensuke/aws-cdk-for-lambda-and-dynamodb-1bn9</guid>
      <description>&lt;p&gt;This post is second post after &lt;a href="https://dev.to/kkkensuke/starting-aws-cdk-with-typescript-aws-lambda-api-gateway-3jhn"&gt;this(Part1)&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Environment
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;AWS Cloud9&lt;/li&gt;
&lt;li&gt;CDK Version : 2.63.2&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Image Diagram
&lt;/h2&gt;

&lt;p&gt;Create a HitCounter Lambda in front of the Lambda (Hello Lambda) created in Part 1. The Hit Counter Lambda accesses DynamoDB and counts up the number of hits.&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%2Fzf5uoze9x6z6tgmwa3tk.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%2Fzf5uoze9x6z6tgmwa3tk.png" alt="Image description" width="585" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So let's get your hands dirty!&lt;/p&gt;

&lt;h2&gt;
  
  
  Create HitCounter
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Define HitCounter Construct
&lt;/h3&gt;

&lt;p&gt;Create a hitcounter.ts file under the lib folder and write the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { Construct } from 'constructs';

export interface HitCounterProps {
  /** the function for which we want to count url hits **/
  downstream: lambda.IFunction;
}

export class HitCounter extends Construct {
  constructor(scope: Construct, id: string, props: HitCounterProps) {
    super(scope, id);

    // TODO
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;A new construct class HitCounter is defined.&lt;/li&gt;
&lt;li&gt;The constructor arguments are scope, id, and props as usual, and we expand it into a cdk.Construct base class.&lt;/li&gt;
&lt;li&gt;A new construct class HitCounter is defined.&lt;/li&gt;
&lt;li&gt;The constructor arguments are scope, id, and props as usual, and we expand it into a cdk.Construct base class.The props argument is of the same type as HitCounterProps and contains one property, downstream of lambda.IFunction, to "plug in" the Hello Lambda function created in Part 1 to this props and count hits.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Create HitCounter Lambda Function
&lt;/h3&gt;

&lt;p&gt;Next, we will create a Lambda function for the hit counter: lambda/hitcounter.js.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const aws = require('aws-sdk')

exports.handler = async function(event) {
  console.log("request:", JSON.stringify(event, undefined, 2));

  // create AWS SDK clients
  const dynamo = new aws.DynamoDB();
  const lambda = new aws.Lambda();

  // update dynamo entry for "path" with hits++
  await dynamo.updateItem({
    TableName: process.env.HITS_TABLE_NAME,
    Key: { path: { S: event.path } },
    UpdateExpression: 'ADD hits :incr',
    ExpressionAttributeValues: { ':incr': { N: '1' } }
  }).promise();

  // call downstream function and capture response
  const resp = await lambda.invoke({
    FunctionName: process.env.DOWNSTREAM_FUNCTION_NAME,
    Payload: JSON.stringify(event)
  }).promise();

  console.log('downstream response:', JSON.stringify(resp, undefined, 2));

  // return response back to upstream caller
  return JSON.parse(resp.Payload);
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;HITS_TABLE_NAME is the name of the DynamoDB table.&lt;/li&gt;
&lt;li&gt;DOWNSTREAM_FUNCTION_NAME is the downstreamed AWS Lambda function name.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since the table names and downstream function names are determined when the app is deployed, these values must be tied to the constructor code. We will implement this in next sections.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add resource to Hit Counter constructor
&lt;/h3&gt;

&lt;p&gt;Now we will add the AWS Lambda function and DynamoDB we created to the Hit Counter constructor. lib/hitcounter.ts will look like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
import { Construct } from 'constructs';

export interface HitCounterProps {
  /** the function for which we want to count url hits **/
  downstream: lambda.IFunction;
}

export class HitCounter extends Construct {

  /** allows accessing the counter function */
  public readonly handler: lambda.Function;

  constructor(scope: Construct, id: string, props: HitCounterProps) {
    super(scope, id);

    const table = new dynamodb.Table(this, 'Hits', {
        partitionKey: { name: 'path', type: dynamodb.AttributeType.STRING }
    });

    this.handler = new lambda.Function(this, 'HitCounterHandler', {
        runtime: lambda.Runtime.NODEJS_14_X,
        handler: 'hitcounter.handler',
        code: lambda.Code.fromAsset('lambda'),
        environment: {
            DOWNSTREAM_FUNCTION_NAME: props.downstream.functionName,
            HITS_TABLE_NAME: table.tableName
        }
    });
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Partition keys for DynamoDB tables are defined as 'path'.&lt;/li&gt;
&lt;li&gt;Defines a Lambda function associated with lambda/hitcounter.handler.&lt;/li&gt;
&lt;li&gt;Lambda environment variables functionName and tableName are associated with this resource.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Add Hit Counter constructor to out stack
&lt;/h3&gt;

&lt;p&gt;Now that the Hit Counter constructor is ready, the next step is to add the constructor to the stack.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as apigw from 'aws-cdk-lib/aws-apigateway';
import { HitCounter } from './hitcounter';

export class CdkWorkshopStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const hello = new lambda.Function(this, 'HelloHandler', {
      runtime: lambda.Runtime.NODEJS_14_X,
      code: lambda.Code.fromAsset('lambda'),
      handler: 'hello.handler'
    });

    const helloWithCounter = new HitCounter(this, 'HelloHitCounter', {
      downstream: hello
    });

    // defines an API Gateway REST API resource backed by our "hello" function.
    new apigw.LambdaRestApi(this, 'Endpoint', {
      handler: helloWithCounter.handler
    });
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The API Gateway handler has been changed to helloWithCounter.handler. Now when a URL is hit, the Hit Counter Lambda is called first, and the Hit Counter Lambda specifies the helloLambda function in the downstream.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploy
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cdk deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will take some time. You should see something like the following as an output&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Outputs:
CdkWorkshopStack.Endpoint8024A810 = https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Test
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -i https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A 502 Bad Gateway error was returned. We will fix what went wrong.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP/2 502 
...

{"message": "Internal server error"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When I refer to the error log from CloudWatch, I see that Lambda is throwing an AccessDeniedException against DynamoDB. It is true that we did not give Lambda permission to access DynamoDB. I will add the following to hitcounter.ts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    // grant the lambda role read/write permissions to our table
    table.grantReadWriteData(this.handler);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, retest!&lt;br&gt;
I got a 502 error again... Another 502 error. This time, I get an AccessDeniedException and an error saying "You don't have enough privileges to invoke!". Add the following to hitcounter.ts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    // grant the lambda role invoke permissions to the downstream function
    props.downstream.grantInvoke(this.handler);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the third time's the charm! We finally succeeded!&lt;br&gt;
(It may take a while for API Gateway to flip the endpoint, so if you get the 502 error again, wait a bit and try again.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP/2 200 OK
...

Hello, CDK! You've hit /
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try it several times.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/
curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/
curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/hello
curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/hello/world
curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/hello/world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's check dynamoDB table.&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%2F6s4y87kbppgpd08s5vv8.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%2F6s4y87kbppgpd08s5vv8.png" alt="Image description" width="317" height="283"&gt;&lt;/a&gt;&lt;br&gt;
It looks good! It counts how many hits against each path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;I think the Hit Counter created this time is a useful service that can be attached to various Lambdas to count how many URLs have been hit for each URL. I think it can be used in actual operations as well!&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://cdkworkshop.com/20-typescript/40-hit-counter.html" rel="noopener noreferrer"&gt;https://cdkworkshop.com/20-typescript/40-hit-counter.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thank you!&lt;/p&gt;

</description>
      <category>startup</category>
      <category>career</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Starting AWS CDK with TypeScript. AWS Lambda + API Gateway</title>
      <dc:creator>kkkensuke</dc:creator>
      <pubDate>Sun, 12 Feb 2023 00:47:58 +0000</pubDate>
      <link>https://dev.to/kkkensuke/starting-aws-cdk-with-typescript-aws-lambda-api-gateway-3jhn</link>
      <guid>https://dev.to/kkkensuke/starting-aws-cdk-with-typescript-aws-lambda-api-gateway-3jhn</guid>
      <description>&lt;h2&gt;
  
  
  Environment
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;AWS Cloud9&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CDK Version : 2.63.2&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Image Diagram
&lt;/h2&gt;

&lt;p&gt;I would like to create a demo of a Lambda service that can be called via Amazon API Gateway using AWS CDK. The demo image is below.&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%2Fyzielf9red7u1g0ajqmj.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%2Fyzielf9red7u1g0ajqmj.png" alt=" " width="625" height="203"&gt;&lt;/a&gt;&lt;br&gt;
So let's get your hands dirty!&lt;/p&gt;
&lt;h2&gt;
  
  
  Creating a new CDK Project
&lt;/h2&gt;

&lt;p&gt;We will be using AWS Cloud9 as our working environment. As the title says, we will create a project using TypeScript.&lt;br&gt;
First, create a directory for the project we will use this time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir cdk-workshop &amp;amp;&amp;amp; cd cdk-workshop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a TypeScript CDK project. (This will take a bit of time.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cdk init sample-app --language typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will see useful cdk commands like this. We will use these later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;## Useful commands

* `cdk deploy`      deploy this stack to your default AWS account/region
* `cdk diff`        compare deployed stack with current state
* `cdk synth`       emits the synthesized CloudFormation template
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will see the project directory created as shown in the figure below.&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%2F1e0sbyjkgtu5fyq3aos6.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%2F1e0sbyjkgtu5fyq3aos6.png" alt=" " width="251" height="319"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;lib/cdk-workshop-stack.ts&lt;/code&gt;:This file defines the main stack of the CDK application. This file is the main file to edit.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;bin/cdk-workshop.ts&lt;/code&gt;:This will be the entry point for the CDK application, loading the stack defined in lib/cdk-workshop-stack.ts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;cdk.json&lt;/code&gt;:It defines how to RUN the app for the toolkit. In this case, it is written as npx ts-node bin/cdk-workshop.ts.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Creating Lambda Function, API Gateway
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Clean up unnecessary code and deploy first time
&lt;/h3&gt;

&lt;p&gt;The first step is to clean up some existing code that is not needed.&lt;br&gt;
Open lib/cdk-workshop-stack.ts and clean up as follows, since SQS Queue and SNS topic are not needed for this demo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import * as cdk from 'aws-cdk-lib';

export class CdkWorkshopStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // nothing here!
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The contents of the CDK are empty, but the AWS CloudFormation template is created (synthesize) from the contents described in the CDK, and when deploying to an AWS environment, even if the CDK is used, the CloudFormation template is deployed in the form of a CloudFormation template.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cdk synth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CloudFormation template has been created in the checkout folder.&lt;/p&gt;

&lt;p&gt;Next, you can install a stack called "bootstrap" only for the first deployment. This stack contains resources used by the CDK Toolkit, such as the S3 bucket that holds the CloudFormation templates.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cdk bootstrap
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's deploy it!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cdk deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you look at the CloudFormation console after a successful deployment, you see that the stack you created exists! (It means that the template created with cdk synth has been applied)&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%2Frfy0yrkvim8agwop2tvk.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%2Frfy0yrkvim8agwop2tvk.png" alt=" " width="618" height="81"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating Hello Lambda function
&lt;/h3&gt;

&lt;p&gt;Let's write the code for the Lambda function. We will do the following&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create a lambda directory in the same hierarchy as the bin and lib directories.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If a .gitignore file exists, add !lambda/*.js in the file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create the file lambda/hello.js and write the following code&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exports.handler = async function(event) {
  console.log("request:", JSON.stringify(event, undefined, 2));
  return {
    statusCode: 200,
    headers: { "Content-Type": "text/plain" },
    body: `Hello, CDK! You've hit ${event.path}\n`
  };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add the created Lambda function to the stack
&lt;/h3&gt;

&lt;p&gt;Add the lambda function you just created to the stack. import the CDK Library for Lambda, which is also needed to add the Lambda stack.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';

export class CdkWorkshopStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // defines an AWS Lambda resource
    const hello = new lambda.Function(this, 'HelloHandler', {
      runtime: lambda.Runtime.NODEJS_16_X,
      code: lambda.Code.fromAsset('lambda'),
      handler: 'hello.handler'
    });
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few additional details about the above code&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The NodeJS (version 16) runtime is used.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The handler of the Lambda function is written to be read from the lambda directory.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The name of the handler is also the same as the handler in the created function.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before deploying, take a look at the differences in the code. You can see the differences.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cdk diff
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deploy
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cdk deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you look at the console after deploy, you will see that the hello.js Lambda function has been created and that the asset folder has also been created in the S3 bucket.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test
&lt;/h3&gt;

&lt;p&gt;To test the created Lambda function, create and run a test using the "Amazon API Gateway AWS Proxy" template from the Lambda console.&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%2Fdy99fxh7g1szc5ole5io.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%2Fdy99fxh7g1szc5ole5io.png" alt=" " width="800" height="382"&gt;&lt;/a&gt;&lt;br&gt;
Looks it works!&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%2Fzj06d5mpw8nh0js45xqo.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%2Fzj06d5mpw8nh0js45xqo.png" alt=" " width="441" height="293"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Creating a API Gateway
&lt;/h3&gt;

&lt;p&gt;Next, we will create an API Gateway, a service that publishes a public endpoint on the Internet, and connect the API Gateway to Lambda so that it can receive requests from browsers and other devices.&lt;br&gt;
The following is a code of the API Gateway.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as apigw from 'aws-cdk-lib/aws-apigateway';

export class CdkWorkshopStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // defines an AWS Lambda resource
    const hello = new lambda.Function(this, 'HelloHandler', {
      runtime: lambda.Runtime.NODEJS_16_X,
      code: lambda.Code.fromAsset('lambda'),
      handler: 'hello.handler'
    });

    // defines an API Gateway REST API resource backed by "hello" function.
    new apigw.LambdaRestApi(this, 'Endpoint', {
      handler: hello
    });
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's look at the differences in the stack.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cdk diff
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see that a lot of resources are created at once, which shows the convenience of the CDK.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Resources
[+] AWS::ApiGateway::RestApi Endpoint EndpointEEF1FD8F 
[+] AWS::ApiGateway::Deployment Endpoint/Deployment EndpointDeployment318525DA5f8cdfe532107839d82cbce31f859259 
[+] AWS::ApiGateway::Stage Endpoint/DeploymentStage.prod EndpointDeploymentStageprodB78BEEA0 
[+] AWS::ApiGateway::Resource Endpoint/Default/{proxy+} Endpointproxy39E2174E 
[+] AWS::Lambda::Permission Endpoint/Default/{proxy+}/ANY/ApiPermission.CdkWorkshopStackEndpoint018E8349.ANY..{proxy+} EndpointproxyANYApiPermissionCdkWorkshopStackEndpoint018E8349ANYproxy747DCA52 
[+] AWS::Lambda::Permission Endpoint/Default/{proxy+}/ANY/ApiPermission.Test.CdkWorkshopStackEndpoint018E8349.ANY..{proxy+} EndpointproxyANYApiPermissionTestCdkWorkshopStackEndpoint018E8349ANYproxy41939001 
[+] AWS::ApiGateway::Method Endpoint/Default/{proxy+}/ANY EndpointproxyANYC09721C5 
[+] AWS::Lambda::Permission Endpoint/Default/ANY/ApiPermission.CdkWorkshopStackEndpoint018E8349.ANY.. EndpointANYApiPermissionCdkWorkshopStackEndpoint018E8349ANYE84BEB04 
[+] AWS::Lambda::Permission Endpoint/Default/ANY/ApiPermission.Test.CdkWorkshopStackEndpoint018E8349.ANY.. EndpointANYApiPermissionTestCdkWorkshopStackEndpoint018E8349ANYB6CC1B64 
[+] AWS::ApiGateway::Method Endpoint/Default/ANY EndpointANY485C938B 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;now, deploy it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cdk deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will see the following URL endpoints as output.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Outputs:
CdkWorkshopStack.Endpoint8024A810 = https://XXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/prod/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you hit this endpoint with the crul command, you'll see the response come back from the Lambda function! You can also try it from your browser.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl https://XXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/prod/
Hello, CDK! You've hit /
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;This time, we created a simple backend app using CDK with API Gateway + Lambda configuration.&lt;br&gt;
Compared to the case where you have to configure it in the console or by writing CloudFormation, it seems that you can complete the creation in a much shorter time. I would like to continue publishing the CDK series in the future.&lt;/p&gt;

&lt;p&gt;Finally, if you want to delete the app you created this time, the following command will clean it up nicely.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cdk destroy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://cdkworkshop.com/20-typescript.html" rel="noopener noreferrer"&gt;https://cdkworkshop.com/20-typescript.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thank you!&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
