<?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>Forem: Allan Chua</title>
    <description>The latest articles on Forem by Allan Chua (@allanchua101).</description>
    <link>https://forem.com/allanchua101</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%2F502894%2Fefad7f59-0566-479f-81fe-1ec4c162204a.jpeg</url>
      <title>Forem: Allan Chua</title>
      <link>https://forem.com/allanchua101</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/allanchua101"/>
    <language>en</language>
    <item>
      <title>How to Import Existing Resources in your CloudFormation Stacks</title>
      <dc:creator>Allan Chua</dc:creator>
      <pubDate>Mon, 27 Nov 2023 16:35:42 +0000</pubDate>
      <link>https://forem.com/aws-builders/how-to-import-existing-resources-in-your-cloudformation-stacks-1a4n</link>
      <guid>https://forem.com/aws-builders/how-to-import-existing-resources-in-your-cloudformation-stacks-1a4n</guid>
      <description>&lt;p&gt;Among challenges that developers and operations staff face while working on CloudFormation is the inability to easily import orphaned stateful resources (S3, DynamoDB, Aurora, OpenSearch, Elastic Search) into CloudFormation stacks. &lt;/p&gt;

&lt;p&gt;This has been a known problem that has been plaguing developers for quite some time. Orphaned CloudFormation resources are often generated through either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Refactoring of a CloudFormation stack that exceeded the maximum number of CloudFormation resources (500 at the time of this article's writing).&lt;/li&gt;
&lt;li&gt;The need to segregate stateful (DynamoDB, S3, SQS, MemoryDB, RDS, etc) vs disposable resources (Lambda, API Gateway, StepFunctions) between multiple CloudFormation stacks.&lt;/li&gt;
&lt;li&gt;The need to convert a POC project that contained both stateful and disposable compute resources in a single CloudFormation stack to comply with production compliance rules of an organization.&lt;/li&gt;
&lt;li&gt;To regroup stateful resources into multiple independent/nested stacks&lt;/li&gt;
&lt;li&gt;To improve deployment efficiency and reduce risk of accidental deletion of stateful resources.&lt;/li&gt;
&lt;li&gt;The need to recover from accidental deletion of CloudFormation stacks that contained stateful resources (DynamoDB, SQS, S3 Buckets, RDS, etc) tagged with &lt;code&gt;DeletionPolicy: Retain&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thankfully, AWS just published a small yet powerful update in CloudFormation ChangeSet API that enables the passing of the &lt;code&gt;ImportExistingResources&lt;/code&gt; parameter.&lt;/p&gt;

&lt;p&gt;As per AWS Blog, &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When you deploy ChangeSets with the ImportExistingResources parameter, CloudFormation automatically imports the resources in your template that already exist in your AWS account. CloudFormation uses the custom names of resources in your template to determine their existence. With this launch, you can reduce the manual effort of import operations and avoid deployment failures because of naming conflicts.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  A hands-on example:
&lt;/h2&gt;

&lt;p&gt;Consider the CloudFormation template below that contains both  a DynamoDB table and an S3 bucket. If you wanna test it out on your own, you may also view this &lt;a href="https://github.com/allanchua101/cf-import-existing-resources-lab" rel="noopener noreferrer"&gt;Github repository&lt;/a&gt; to play around it.&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;AWSTemplateFormatVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2010-09-09&lt;/span&gt;

&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;LionDDBTable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::DynamoDB::Table&lt;/span&gt;
    &lt;span class="na"&gt;DeletionPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Retain&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;TableName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;my-lion-ddb"&lt;/span&gt;
      &lt;span class="na"&gt;AttributeDefinitions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;AttributeName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ID&lt;/span&gt;
          &lt;span class="na"&gt;AttributeType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;S&lt;/span&gt;
      &lt;span class="na"&gt;KeySchema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;AttributeName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ID&lt;/span&gt;
          &lt;span class="na"&gt;KeyType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HASH&lt;/span&gt;
      &lt;span class="na"&gt;ProvisionedThroughput&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;ReadCapacityUnits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
        &lt;span class="na"&gt;WriteCapacityUnits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;

  &lt;span class="na"&gt;LionS3Bucket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::S3::Bucket&lt;/span&gt;
    &lt;span class="na"&gt;DeletionPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Retain&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Replace this bucket name as S3 &lt;/span&gt;
      &lt;span class="c1"&gt;# bucket names are expected to be &lt;/span&gt;
      &lt;span class="c1"&gt;# globally unique&lt;/span&gt;
      &lt;span class="na"&gt;BucketName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;acsg-test-lion-bucket"&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;If the CloudFormation stack defined above gets deleted, both the S3 bucket and the DynamoDB tables will be retained thanks to the &lt;code&gt;DeletionPolicy&lt;/code&gt; configured with &lt;code&gt;Retain&lt;/code&gt; strategy. &lt;/p&gt;

&lt;p&gt;This behaviour is great if the only goal for operating these resources is to make sure that data does not get dropped maliciously. One of the downsides of deploying this strategy is that we couldn't easily import back these resources in new CloudFormation stacks. &lt;/p&gt;

&lt;p&gt;To prove this, run the following CloudFormation stack creation script:&lt;/p&gt;

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

&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
aws cloudformation create-stack &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--stack-name&lt;/span&gt; &lt;span class="s2"&gt;"petshop-stateful-stack"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--template-body&lt;/span&gt; file:///&lt;span class="nv"&gt;$PWD&lt;/span&gt;/template.cfn.yaml &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--capabilities&lt;/span&gt; CAPABILITY_IAM &lt;span class="se"&gt;\&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;After the deployment is done, you can run the following stack destruction script:&lt;/p&gt;

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

&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
aws cloudformation delete-stack &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--stack-name&lt;/span&gt;  &lt;span class="s2"&gt;"petshop-stateful-stack"&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Since both our S3 and DynamoDB tables are configured with &lt;code&gt;DeletionPolicy: Retain&lt;/code&gt; settings, you can expect to still see them in their respective consoles despite the parent CloudFormation stack's deletion.&lt;/p&gt;

&lt;p&gt;If you re-run the &lt;code&gt;aws cloudformation create-stack&lt;/code&gt; CLI call from the previous step, you'll get the following error from CloudFormation:&lt;/p&gt;

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

Resource handler returned message: 
"Resource of type 'AWS::DynamoDB::Table' 
with identifier 'my-lion-ddb' already exists." 
(RequestToken: 016e3290-588c-09f9-a92e-497ae81f9e49, HandlerErrorCode: AlreadyExists)


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

&lt;/div&gt;

&lt;p&gt;IMHO, it will be a huge development boost if we can also get the &lt;code&gt;--import-existing-resources&lt;/code&gt; flag for the &lt;code&gt;aws cloudformation create-stack&lt;/code&gt; CLI invocation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using ChangeSets and ImportExistingResources Parameter
&lt;/h2&gt;

&lt;p&gt;To automatically recreate the stack and import the pre-existing resources that were orphaned by the destroy step, we can create a &lt;code&gt;create-change-set&lt;/code&gt; API call via AWS CLI and pass the &lt;code&gt;--import-existing-resources&lt;/code&gt; parameter. &lt;/p&gt;

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

&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="c"&gt;# Define variables&lt;/span&gt;
&lt;span class="nv"&gt;stack_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"petshop-stateful-stack"&lt;/span&gt;
&lt;span class="nv"&gt;template_file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PWD&lt;/span&gt;&lt;span class="s2"&gt;/template.cfn.yaml"&lt;/span&gt;
&lt;span class="nv"&gt;change_set_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"change-set-&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%s&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Create a change set&lt;/span&gt;
aws cloudformation create-change-set &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--stack-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$stack_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--change-set-type&lt;/span&gt; &lt;span class="s2"&gt;"CREATE"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--change-set-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$change_set_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--template-body&lt;/span&gt; &lt;span class="s2"&gt;"file://&lt;/span&gt;&lt;span class="nv"&gt;$template_file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--capabilities&lt;/span&gt; CAPABILITY_IAM &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--import-existing-resources&lt;/span&gt; &lt;span class="c"&gt;# Life saving parameter&lt;/span&gt;

&lt;span class="c"&gt;# Describe the change set (optional)&lt;/span&gt;
aws cloudformation describe-change-set &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--stack-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$stack_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--change-set-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$change_set_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Execute the change set&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Do you want to execute this change set? (yes/no)"&lt;/span&gt;
&lt;span class="nb"&gt;read &lt;/span&gt;execute_decision

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$execute_decision&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"yes"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;aws cloudformation execute-change-set &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--stack-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$stack_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--change-set-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$change_set_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Change set executed."&lt;/span&gt;
&lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Change set not executed."&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Upon the execution of the changeset, you'll be seeing "Import Complete" operations in your CloudFormation stacks.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Things to keep in mind
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;You'll need the latest AWS CLI version to use this feature. I'm using AWS CLI version 2.13.38 at the time of this article's writing.&lt;/li&gt;
&lt;li&gt;The stateful resources needs to have a &lt;code&gt;DeletionPolicy&lt;/code&gt; property configured in it and have a unique name defined on the resource.&lt;/li&gt;
&lt;li&gt;You can't import resources into multiple CloudFormation stacks.&lt;/li&gt;
&lt;li&gt;CloudFormation max resource count limitation (500 at the time of writing) applies to import operations.&lt;/li&gt;
&lt;li&gt;You can use the &lt;code&gt;cloudformation:ImportResourceTypes&lt;/code&gt; policy condition to define IAM policies that control which resource types principals can run import operations on.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Benefits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;We now have the option to delete CloudFormation stacks that contains stateful resources as long as they are properly configured with &lt;code&gt;DeletionPolicy: Retain&lt;/code&gt; property&lt;/li&gt;
&lt;li&gt;It is now possible to easily refactor, regroup and transfer resources across new and existing CloudFormation stacks on-demand.&lt;/li&gt;
&lt;li&gt;Less ClickOps related to importing existing resources to CloudFormation stacks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Related Links:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/allanchua101/cf-import-existing-resources-lab" rel="noopener noreferrer"&gt;Github POC Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/about-aws/whats-new/2023/11/aws-cloudformation-import-parameter-changesets/" rel="noopener noreferrer"&gt;AWS CloudFormation simplifies resource import with a new parameter for ChangeSets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resource-import.html" rel="noopener noreferrer"&gt;Bringing existing resources into CloudFormation management
&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devops</category>
      <category>aws</category>
      <category>cloudformation</category>
      <category>dataengineering</category>
    </item>
    <item>
      <title>Scaffolding a Vue 3 + Vuetify + Amplify Project (2023)</title>
      <dc:creator>Allan Chua</dc:creator>
      <pubDate>Sun, 09 Apr 2023 04:10:43 +0000</pubDate>
      <link>https://forem.com/aws-builders/scaffolding-vue-3-projects-using-amplify-2023-g35</link>
      <guid>https://forem.com/aws-builders/scaffolding-vue-3-projects-using-amplify-2023-g35</guid>
      <description>&lt;p&gt;This article aims to provide the most recent step by step guide on how to scaffold a base project using Vue 3, Vuetify and Amplify components. Using amplify's Vue 3 getting started tutorial was a bit challenging in my opinion as certain steps (Injection of &lt;code&gt;window.global&lt;/code&gt; script in index.html was confusing, &lt;code&gt;vite.config.js&lt;/code&gt; setup was lacking import alias support, directory where &lt;code&gt;amplify init&lt;/code&gt; should be triggered isn't clearly stated) on the guide were not detailed enough to be followed by somebody completely new with using Amplify.&lt;/p&gt;

&lt;p&gt;After reading through this article, you'd be able to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run &lt;code&gt;npm run dev&lt;/code&gt; successfully without facing import issues.&lt;/li&gt;
&lt;li&gt;Get an amplify app in your AWS account.&lt;/li&gt;
&lt;li&gt;Have a base scaffold that could easily be extended with other core amplify components (GraphQL API, Hosting, Cognito-based Auth)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Pre-requisites
&lt;/h3&gt;

&lt;p&gt;In order to follow this guide and the same exact scaffold, you will need to have the following CLIs installed on your machines.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Node 18&lt;/code&gt; - I'm using the most latest version of NodeJS 18. I've installed mine using &lt;code&gt;nvm&lt;/code&gt; (Node version manager).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;amplify&lt;/code&gt; cli - You'll need the amplify cli to initialize the amplify app and provision backend resources later on.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;aws&lt;/code&gt; cli - You'll need an AWS cli to configure pre-built AWS profiles that allows your machine to make changes on your AWS accounts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Initialise the Vue 3 projects
&lt;/h3&gt;

&lt;p&gt;As with any Vue 3 + Vite project, we have to scaffold the base project by using the pre-built tools provided by the Vue JS.&lt;/p&gt;

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

npm init vue@3


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Install Dependencies
&lt;/h3&gt;

&lt;p&gt;After the scaffolding of base components gets completed, navigate into the project's directory and install the dependencies required by the base application to run.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# Substitute this with your project name&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ./aws-exam-trainer

npm &lt;span class="nb"&gt;install&lt;/span&gt;


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Add Dependencies
&lt;/h3&gt;

&lt;p&gt;We also need to install the following dependencies:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;vuetify&lt;/code&gt; - is the most popular UI library for VueJS projects. It requires literally no design skills to get you started in crafting visually decent frontend applications.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;aws-amplify&lt;/code&gt; - is the base library used for accessing common integrations in Amplify such as API, Auth, Analytics, etc. This library is not coupled with UI-specific frameworks such as Vue and React JS.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@aws-amplify/ui-vue&lt;/code&gt; - is a VueJS-specific set of cloud connected components that makes trivial tasks (Upload to S3, Cognito-backed Integration, etc) easy and fast to implement.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npm &lt;span class="nb"&gt;install &lt;/span&gt;vuetify aws-amplify @aws-amplify/ui-vue


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Initialising Amplify App
&lt;/h3&gt;

&lt;p&gt;The next step is to initialise the Amplify app. This is done by running the &lt;code&gt;amplify init&lt;/code&gt; command inside the directory generated by the &lt;code&gt;npm init vue@3&lt;/code&gt; command from the first step.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

amplify init


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

&lt;/div&gt;

&lt;p&gt;Running the command will present you with the following prompt and most of the configurations for vue 3 projects will be pre-filled for us. Just agree with the default configurations for now.&lt;/p&gt;

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

Note: It is recommended to run this &lt;span class="nb"&gt;command &lt;/span&gt;from the root of your app directory
? Enter a name &lt;span class="k"&gt;for &lt;/span&gt;the project awsexamtrainer
The following configuration will be applied:

Project information
| Name: awsexamtrainer
| Environment: dev
| Default editor: Visual Studio Code
| App &lt;span class="nb"&gt;type&lt;/span&gt;: javascript
| Javascript framework: vue
| Source Directory Path: src
| Distribution Directory Path: dist
| Build Command: npm run-script build
| Start Command: npm run-script serve

? Initialize the project with the above configuration? Yes
Using default provider  awscloudformation


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

&lt;/div&gt;

&lt;p&gt;The next important step is to configure the AWS named profile that will be used for provisioning the Amplify app. This profile will also be used for other operations that require changes to our AWS account, such as provisioning AppSync APIs and Cognito User Pools.&lt;/p&gt;

&lt;p&gt;In my machine, I've configured a profile called &lt;code&gt;my-poc-profile&lt;/code&gt; and just selected this on the guided CLI provided by AWS amplify&lt;/p&gt;

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

? Select the authentication method you want to use: AWS profile

For more information on AWS Profiles, see:
https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html

? Please choose the profile you want to use my-poc-profile
Adding backend environment dev to AWS Amplify app: dvmifg83sjtwe

Deployment completed.
Deploying root stack awsexamtrainer &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;----------------------------------------&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; 0/4
        amplify-awsexamtrainer-dev-10… AWS::CloudFormation::Stack     CREATE_IN_PROGRESS             Sun Apr 09 2023 10:08:18…     
        DeploymentBucket               AWS::S3::Bucket                CREATE_IN_PROGRESS             Sun Apr 09 2023 10:08:21…     
        AuthRole                       AWS::IAM::Role                 CREATE_IN_PROGRESS             Sun Apr 09 2023 10:08:21…     
        UnauthRole                     AWS::IAM::Role                 CREATE_IN_PROGRESS             Sun Apr 09 2023 10:08:21…     

✔ Help improve Amplify CLI by sharing non sensitive configurations on failures &lt;span class="o"&gt;(&lt;/span&gt;y/N&lt;span class="o"&gt;)&lt;/span&gt; · no
Deployment state saved successfully.
✔ Initialized provider successfully.
✅ Initialized your environment successfully.

Your project has been successfully initialized and connected to the cloud!

Some next steps:
&lt;span class="s2"&gt;"amplify status"&lt;/span&gt; will show you what you&lt;span class="s1"&gt;'ve added already and if it'&lt;/span&gt;s locally configured or deployed
&lt;span class="s2"&gt;"amplify add &amp;lt;category&amp;gt;"&lt;/span&gt; will allow you to add features like user login or a backend API
&lt;span class="s2"&gt;"amplify push"&lt;/span&gt; will build all your &lt;span class="nb"&gt;local &lt;/span&gt;backend resources and provision it &lt;span class="k"&gt;in &lt;/span&gt;the cloud
&lt;span class="s2"&gt;"amplify console"&lt;/span&gt; to open the Amplify Console and view your project status
&lt;span class="s2"&gt;"amplify publish"&lt;/span&gt; will build all your &lt;span class="nb"&gt;local &lt;/span&gt;backend and frontend resources &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;you have hosting category added&lt;span class="o"&gt;)&lt;/span&gt; and provision it &lt;span class="k"&gt;in &lt;/span&gt;the cloud

Pro tip:
Try &lt;span class="s2"&gt;"amplify add api"&lt;/span&gt; to create a backend API and &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="s2"&gt;"amplify push"&lt;/span&gt; to deploy everything


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

&lt;/div&gt;

&lt;p&gt;At this point, you should now have an amplify app configured on your AWS account.&lt;/p&gt;

&lt;h3&gt;
  
  
  Plug Vuetify and Amplify to main.js file
&lt;/h3&gt;

&lt;p&gt;In order to access Vuetify UI components and Amplify base libraries, we'll have to configure the default &lt;code&gt;main.js&lt;/code&gt; file generated by the vue init process with the following code.&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createApp&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;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&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;./App.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;router&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;./router&lt;/span&gt;&lt;span class="dl"&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;./assets/main.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// Vuetify&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;vuetify/styles&lt;/span&gt;&lt;span class="dl"&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;createVuetify&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;vuetify&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;components&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;vuetify/components&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;directives&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;vuetify/directives&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// Amplify&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;Amplify&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;aws-amplify&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;awsExports&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;./aws-exports&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;AmplifyVue&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;@aws-amplify/ui-vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;Amplify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;awsExports&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;vuetify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createVuetify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;directives&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;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vuetify&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AmplifyVue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Add window.global and global exports handle (Vite Users only) to index.html
&lt;/h3&gt;

&lt;p&gt;In order to make use of the UI components provided by &lt;code&gt;@aws-amplify/ui-vue&lt;/code&gt; library to our vite-based project, we'll have to inject the snippet below that adds &lt;code&gt;global&lt;/code&gt; property to window and a global exports object required by Amplify components. &lt;/p&gt;

&lt;p&gt;Please inject it on the same position to avoid getting unwanted behaviours and errors later on the development. (This is one nasty mistake I've made on my initial attempts on using Amplify + VueJS projects).&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/favicon.ico"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Vite App&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"app"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!--Add this snippet--&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;global&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!--End of snippet to inject--&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/src/main.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Setup vite.config.js
&lt;/h2&gt;

&lt;p&gt;We'll also have to configure the &lt;code&gt;vite.config.js&lt;/code&gt; file so it would end up like this instead of the one provided by the amplify getting started docs for Vue JS. &lt;/p&gt;

&lt;p&gt;What makes this configuration better than the one provided by the amplify team is that it allows us to import vue components from &lt;code&gt;src&lt;/code&gt; folder without having to use relative paths.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tip of the day&lt;/strong&gt;&lt;br&gt;
Importing components using static path syntax makes VueJS projects easier to maintain by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Making refactoring of dependent components paths in large projects more resilient to bugs caused by relative imports failures.&lt;/li&gt;
&lt;li&gt;Regardless of the depth of the dependent component, static path imports make it easy reference shared components by having a standard import location.&lt;/li&gt;
&lt;li&gt;Removes the cognitive effort required from developers in mentally resolving the relative paths of components they like to import.&lt;/li&gt;
&lt;/ul&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&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;vite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;vue&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;@vitejs/plugin-vue&lt;/span&gt;&lt;span class="dl"&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;fileURLToPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;URL&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;url&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// https://vitejs.dev/config/&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;vue&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
  &lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;alias&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;find&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./runtimeConfig&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;replacement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./runtimeConfig.browser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="c1"&gt;// This bit here is not mentioned in Amplify Docs&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;find&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;replacement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;fileURLToPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src&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;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&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="p"&gt;})&lt;/span&gt;


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  For TypeScript users
&lt;/h3&gt;

&lt;p&gt;For typescript users, you will have to configure the &lt;code&gt;compilerOptions.skipLibCheck&lt;/code&gt; option to your &lt;code&gt;tsconfig.json&lt;/code&gt; files to skip type checking of declaration files.&lt;/p&gt;

&lt;p&gt;This can save time during compilation at the expense of type-system accuracy. For example, two libraries could define two copies of the same type in an inconsistent way. Rather than doing a full check of all &lt;code&gt;d.ts&lt;/code&gt; files, TypeScript will type check the code you specifically refer to in your app’s source code.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&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;"skipLibCheck"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Testing the Base Scaffold
&lt;/h3&gt;

&lt;p&gt;At this point, you should have a basic Vue 3 project that can access both Vuetify and Amplify components without facing compile issues.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npm run dev


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

&lt;/div&gt;

&lt;p&gt;You should be able to see the following web page on the port allocated to vite without errors.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  What's Next?
&lt;/h3&gt;

&lt;p&gt;On the next articles, I'll be showcasing how to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install and customize a Cognito-backed login interface.&lt;/li&gt;
&lt;li&gt;Add an AppSync API that uses at least two types of resolvers (Lambda and DynamoDB)&lt;/li&gt;
&lt;li&gt;Automate the deployment of changes from github repos to S3+CloudFront web hosting setup.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The final project aims to generate AWS exam reviewer questions using OpenAI prompts based from a user provided link (Ideally an AWS Documentation web page). &lt;/p&gt;

&lt;p&gt;What makes this project interesting is that AWS professionals can now generate reviewer questions in a matter of seconds, track their scores and generate reviewer content that changes over time. &lt;/p&gt;

&lt;p&gt;Till then, see you soon.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>amplify</category>
      <category>vue</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Preventing Accidental Deletion of DynamoDBs using Table Protection Strategy Feature (March 2023)</title>
      <dc:creator>Allan Chua</dc:creator>
      <pubDate>Thu, 09 Mar 2023 05:35:43 +0000</pubDate>
      <link>https://forem.com/aws-builders/preventing-accidental-deletion-of-dynamodb-using-table-protection-strategy-feature-march-2023-56ck</link>
      <guid>https://forem.com/aws-builders/preventing-accidental-deletion-of-dynamodb-using-table-protection-strategy-feature-march-2023-56ck</guid>
      <description>&lt;p&gt;DynamoDB is the most popular NoSQL database service provided by AWS. It is considered as the de facto choice for storage of serverless-based projects because of its highly scalable, durable, and available nature. &lt;/p&gt;

&lt;p&gt;DynamoDB traditionally offered various mechanisms that could be used to protect both the table and data contained in them which included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Usage of IAM-based &lt;a href="https://aws.amazon.com/blogs/database/use-guardrails-to-protect-dynamodb-tables/" rel="noopener noreferrer"&gt;guardrails&lt;/a&gt; to deny delete operations on DynamoDB tables.&lt;/li&gt;
&lt;li&gt;CloudFormation resource &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-deletionpolicy.html" rel="noopener noreferrer"&gt;deletion policy&lt;/a&gt; which prevents CloudFormation tools from deleting your Dynamo DB tables when deleting a stack.&lt;/li&gt;
&lt;li&gt;Point-in-time-recovery &lt;a href="https://aws.amazon.com/dynamodb/pitr/" rel="noopener noreferrer"&gt;(PITR)&lt;/a&gt; feature which allows continuous backup of data on a second-based granularity for the past 35 days.&lt;/li&gt;
&lt;li&gt;On-demand &lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/BackupRestore.html" rel="noopener noreferrer"&gt;backup and restore &lt;/a&gt;which allows us to handle data restoration beyond the 35 days limitation of PITR capability.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/backuprestore_HowItWorksAWS.html" rel="noopener noreferrer"&gt;AWS Backup for DynamoDB&lt;/a&gt; which allows organizations to align their backup policies and management strategies with other storage resources.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, one feature that has been requested by end-users is "Deletion Protection" that is highly comparable with EC2 and RDS deletion protection options. The status quo changed today as &lt;a href="https://aws.amazon.com/blogs/database/how-to-use-deletion-protection-to-enhance-your-amazon-dynamodb-table-protection-strategy/" rel="noopener noreferrer"&gt;AWS announced&lt;/a&gt; the feature as a response to customer demand.&lt;/p&gt;

&lt;p&gt;If you visit the new DynamoDB console, you can now find a feature that enables you to turn on the deletion protection flag.&lt;/p&gt;

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

&lt;p&gt;The list of tables in DynamoDB console now includes a column that indicates protection status for each DynamoDB table:&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Using AWS CLI
&lt;/h3&gt;

&lt;p&gt;You can also start applying protection status on new tables using  CLI-based commands as the documentation on how to implement this has been published:&lt;/p&gt;

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

&lt;p&gt;You would have to update your version of AWS CLI to get hold of this feature:&lt;/p&gt;

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

pip3 &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--upgrade&lt;/span&gt; awscli

aws &lt;span class="nt"&gt;--version&lt;/span&gt;

&lt;span class="c"&gt;# aws-cli/2.7.19 Python/3.9.11 Darwin/22.3.0 exe/x86_64 prompt/off&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;After making sure your CLI version is of at least 2.7.19, you can now run the following shell command to test out the feature:&lt;/p&gt;


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

&lt;p&gt;aws dynamodb create-table &lt;span class="se"&gt;&amp;lt;/span&amp;gt;&lt;br&gt;
    &lt;span class="nt"&gt;--table-name&lt;/span&gt; &lt;span class="s2"&gt;"cant-delete-db"&lt;/span&gt; &lt;span class="se"&gt;&amp;lt;/span&amp;gt;&lt;br&gt;
    &lt;span class="nt"&gt;--attribute-definitions&lt;/span&gt; &lt;span class="se"&gt;&amp;lt;/span&amp;gt;&lt;br&gt;
        &lt;span class="nv"&gt;AttributeName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ID,AttributeType&lt;span class="o"&gt;=&lt;/span&gt;S &lt;span class="se"&gt;&amp;lt;/span&amp;gt;&lt;br&gt;
        &lt;span class="nv"&gt;AttributeName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;DeleteOpName,AttributeType&lt;span class="o"&gt;=&lt;/span&gt;S &lt;span class="se"&gt;&amp;lt;/span&amp;gt;&lt;br&gt;
    &lt;span class="nt"&gt;--key-schema&lt;/span&gt; &lt;span class="se"&gt;&amp;lt;/span&amp;gt;&lt;br&gt;
        &lt;span class="nv"&gt;AttributeName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ID,KeyType&lt;span class="o"&gt;=&lt;/span&gt;HASH &lt;span class="se"&gt;&amp;lt;/span&amp;gt;&lt;br&gt;
        &lt;span class="nv"&gt;AttributeName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;DeleteOpName,KeyType&lt;span class="o"&gt;=&lt;/span&gt;RANGE &lt;span class="se"&gt;&amp;lt;/span&amp;gt;&lt;br&gt;
    &lt;span class="nt"&gt;--provisioned-throughput&lt;/span&gt; &lt;span class="se"&gt;&amp;lt;/span&amp;gt;&lt;br&gt;
        &lt;span class="nv"&gt;ReadCapacityUnits&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5,WriteCapacityUnits&lt;span class="o"&gt;=&lt;/span&gt;5 &lt;span class="se"&gt;&amp;lt;/span&amp;gt;&lt;br&gt;
    &lt;span class="nt"&gt;--deletion-protection-enabled&lt;/span&gt; &lt;span class="se"&gt;&amp;lt;/span&amp;gt;&lt;br&gt;
    &lt;span class="nt"&gt;--table-class&lt;/span&gt; STANDARD &lt;span class="se"&gt;&amp;lt;/span&amp;gt;&lt;br&gt;
    &lt;span class="nt"&gt;--profile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"my-poc-profile"&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  CloudFormation&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;DynamoDB CloudFormation template now supports delete protection flag. This could be done by specifying the &lt;code&gt;DeletionProtectionEnabled&lt;/code&gt; property to true.&lt;/p&gt;


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

&lt;p&gt;&lt;span class="na"&gt;SampleTable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::DynamoDB::Table&lt;/span&gt;&lt;br&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
      &lt;span class="na"&gt;TableName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;my-delete-resilient-db"&lt;/span&gt;&lt;br&gt;
      &lt;span class="na"&gt;BillingMode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PAY_PER_REQUEST&lt;/span&gt;&lt;br&gt;
      &lt;span class="na"&gt;DeletionProtectionEnabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;# Focus here&lt;/span&gt;&lt;br&gt;
      &lt;span class="na"&gt;SSESpecification&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
        &lt;span class="na"&gt;SSEEnabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;br&gt;
      &lt;span class="na"&gt;AttributeDefinitions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;AttributeName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;id&lt;/span&gt;&lt;br&gt;
          &lt;span class="na"&gt;AttributeType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;S&lt;/span&gt;&lt;br&gt;
      &lt;span class="na"&gt;KeySchema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;AttributeName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;id&lt;/span&gt;&lt;br&gt;
          &lt;span class="na"&gt;KeyType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HASH&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Terraform&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;Terraform update was released 1 week later at &lt;a href="https://github.com/hashicorp/terraform-provider-aws/releases/tag/v4.59.0" rel="noopener noreferrer"&gt;March 17, 2023&lt;/a&gt;.&lt;/p&gt;


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

&lt;p&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_dynamodb_table"&lt;/span&gt; &lt;span class="s2"&gt;"basic-dynamodb-table"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;                        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"GameScores"&lt;/span&gt;&lt;br&gt;
  &lt;span class="nx"&gt;billing_mode&lt;/span&gt;                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"PROVISIONED"&lt;/span&gt;&lt;br&gt;
  &lt;span class="nx"&gt;deletion_protection_enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;br&gt;
  &lt;span class="nx"&gt;hash_key&lt;/span&gt;                    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"UserId"&lt;/span&gt;&lt;br&gt;
  &lt;span class="nx"&gt;range_key&lt;/span&gt;                   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"GameTitle"&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="nx"&gt;attribute&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"UserId"&lt;/span&gt;&lt;br&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"S"&lt;/span&gt;&lt;br&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="nx"&gt;attribute&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"GameTitle"&lt;/span&gt;&lt;br&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"S"&lt;/span&gt;&lt;br&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  CDK&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;At the time of this writing, there is still no or documentation updates that has been published from CDK provider. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update March 20, 2023&lt;/strong&gt; there's been a new &lt;a href="https://github.com/aws/aws-cdk/pull/24581" rel="noopener noreferrer"&gt;pull request&lt;/a&gt; in Github for DynamoDB delete protection and will be published soon in CDK and CDK DynamoDB documentation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update March 22, 2023&lt;/strong&gt; &lt;a href="https://github.com/aws/aws-cdk/pull/24581" rel="noopener noreferrer"&gt;pull request&lt;/a&gt; was merged, still no documentation updates.&lt;/p&gt;

&lt;p&gt;Below is a preview of how could you do it in CDK upon release.&lt;/p&gt;


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

&lt;p&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;table&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;dynamodb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Table&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;br&gt;
  &lt;span class="na"&gt;partitionKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AttributeType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;&lt;br&gt;
  &lt;span class="na"&gt;deletionProtection&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;br&gt;
&lt;span class="p"&gt;});&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Key Benefits&lt;br&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multiple developers working on the same table:&lt;/strong&gt; In a team environment, multiple developers may be working on the same DynamoDB table. Without proper access controls and protection strategies, there is a risk of accidental deletions or modifications that could impact the entire team's work. By using Table Protection Strategy, you can prevent accidental deletions and maintain the integrity of the table, even with multiple developers working on it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Testing and development environments:&lt;/strong&gt; In testing and development environments, there may be a need to create and delete tables frequently. However, this also increases the risk of accidentally deleting important data or tables. By using Table Protection Strategy, you can prevent accidental deletions and ensure that your data remains intact during the testing and development process.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Compliance requirements:&lt;/strong&gt; Depending on your industry and regulatory requirements, you may need to have additional protections in place to prevent accidental deletions or modifications of data. By using Table Protection Strategy, you can demonstrate that you have taken appropriate measures to protect your data and comply with regulatory requirements.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Production environments:&lt;/strong&gt; In a production environment, accidental deletions can have serious consequences, including data loss and downtime. By using Table Protection Strategy, you can prevent accidental deletions and ensure that your tables remain available and operational.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Overall, using Table Protection Strategy in DynamoDB can help you reduce the risk of data loss, maintain data integrity, and ensure compliance with regulatory requirements.&lt;/p&gt;

</description>
      <category>dynamodb</category>
      <category>cloud</category>
      <category>devops</category>
      <category>aws</category>
    </item>
    <item>
      <title>How to Retrieve All DynamoDB Tables in a Single Account using JavaScript SDK v3 (2023)</title>
      <dc:creator>Allan Chua</dc:creator>
      <pubDate>Wed, 08 Mar 2023 06:02:16 +0000</pubDate>
      <link>https://forem.com/aws-builders/how-to-retrieve-all-dynamodb-tables-using-javascript-sdk-v3-2023-4bbm</link>
      <guid>https://forem.com/aws-builders/how-to-retrieve-all-dynamodb-tables-using-javascript-sdk-v3-2023-4bbm</guid>
      <description>&lt;p&gt;In an engineering team with matured devops practices, it is  often required to know all the DynamoDBs running in various accounts. This list of tables could then be used for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Performing standard compliance checks on your table names and configuration.&lt;/li&gt;
&lt;li&gt;Build alarm systems that monitors list of tables in a production account to make sure that every single table you need exists.&lt;/li&gt;
&lt;li&gt;Creating backups and restoring data in DynamoDB tables.&lt;/li&gt;
&lt;li&gt;Managing and organizing your DynamoDB tables.&lt;/li&gt;
&lt;li&gt;Monitoring and optimizing performance of your DynamoDB tables.&lt;/li&gt;
&lt;li&gt;Automating and integrating your application with other AWS services that use DynamoDB tables as input or output.&lt;/li&gt;
&lt;li&gt;Auditing and tracking usage of your DynamoDB tables.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this article, we'll be exploring how to retrieve all the DynamoDB table names using AWS SDK for JavaScript v3. &lt;/p&gt;

&lt;h2&gt;
  
  
  Before you start
&lt;/h2&gt;

&lt;p&gt;I'd recommend using the latest version of NodeJS supported by Lambda Functions. It's also helpful to have nvm in your machine to easily switch between NodeJS versions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install Node 18 to use the latest code-base&lt;/span&gt;
nvm &lt;span class="nb"&gt;install &lt;/span&gt;18

node &lt;span class="nt"&gt;--version&lt;/span&gt;

&lt;span class="c"&gt;# Switch to NodeJS 18&lt;/span&gt;
nvm use 18
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will have to install the JavaScript AWS SDKs v3 for DynamoDB. If you are using NPM, use the following commands to install the SDKs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# If you use NPM&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; @aws-sdk/client-dynamodb

&lt;span class="c"&gt;# Install only if you want to use &lt;/span&gt;
&lt;span class="c"&gt;# named profiles inside your dev machine&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; @aws-sdk/credential-providers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you need to use yarn:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# If you use yarn&lt;/span&gt;
yarn add @aws-sdk/client-dynamodb

&lt;span class="c"&gt;# Install only if you want to use inside your dev machine&lt;/span&gt;
yarn add @aws-sdk/credential-providers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Source Code
&lt;/h2&gt;

&lt;p&gt;By design, ListTablesCommand can only return a maximum of 100 DynamoDB names from a single AWS region (see the code below).&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DynamoDBClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ListTablesCommand&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="s2"&gt;@aws-sdk/client-dynamodb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fromIni&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="s2"&gt;@aws-sdk/credential-providers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;DynamoDBClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ap-southeast-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Use this code if you need named profiles&lt;/span&gt;
&lt;span class="c1"&gt;// const client = new DynamoDBClient({&lt;/span&gt;
&lt;span class="c1"&gt;//   credentials: fromIni({ profile: "my-poc-profile" }),&lt;/span&gt;
&lt;span class="c1"&gt;//   region: "ap-southeast-1",&lt;/span&gt;
&lt;span class="c1"&gt;// });&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ListTablesCommand&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;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which would result to the following JSON response. The response below contains all the DynamoDB tables in a single region (In our case &lt;code&gt;ap-southeast-1&lt;/code&gt;):&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="err"&gt;'$metadata':&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="err"&gt;httpStatusCode:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;requestId:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'LKJEWJOI&lt;/span&gt;&lt;span class="mi"&gt;3290923902302310219&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;extendedRequestId:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;cfId:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;attempts:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;totalRetryDelay:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;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="err"&gt;LastEvaluatedTableName:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;TableNames:&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="err"&gt;'dynamo-table-a'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="err"&gt;'dynamo-table-b'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="err"&gt;'dynamo-table-c'&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The page limitation of 100 items per response is probably placed by AWS to gracefully handle accounts with large number of DynamoDB tables in them.&lt;/p&gt;

&lt;p&gt;If you really want to retrieve all the tables in a single region of a single account. You can use the following code instead:&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DynamoDBClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ListTablesCommand&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="s2"&gt;@aws-sdk/client-dynamodb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fromIni&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="s2"&gt;@aws-sdk/credential-providers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;DynamoDBClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fromIni&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-poc-profile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ap-southeast-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;startTableName&lt;/span&gt; &lt;span class="o"&gt;=&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;hasResults&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&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;tableNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;hasResults&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&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;searchInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;Limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&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;startTableName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;searchInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ExclusiveStartTableName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;startTableName&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;command&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;ListTablesCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchInput&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;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&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;TableNames&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&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;TableNames&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;startTableName&lt;/span&gt; &lt;span class="o"&gt;=&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;TableNames&lt;/span&gt;&lt;span class="p"&gt;[&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;TableNames&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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="nx"&gt;tableNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;tableNames&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&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;TableNames&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nx"&gt;hasResults&lt;/span&gt; &lt;span class="o"&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="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hasResults&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="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tableNames&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Which would result to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;'dynamo-table-a'&lt;/span&gt;, &lt;span class="s1"&gt;'dynamo-table-b'&lt;/span&gt;, &lt;span class="s1"&gt;'dynamo-table-c'&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To improve the re-usability of this code, we can export it into a modular function that looks like:&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DynamoDBClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ListTablesCommand&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="s2"&gt;@aws-sdk/client-dynamodb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fromIni&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="s2"&gt;@aws-sdk/credential-providers&lt;/span&gt;&lt;span class="dl"&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getAllDynamoDBTableNamesV3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;region&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;clientConfig&lt;/span&gt; &lt;span class="o"&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;profile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;clientConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;credentials&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fromIni&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;profile&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;region&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;clientConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;region&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;region&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;client&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;DynamoDBClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clientConfig&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;startTableName&lt;/span&gt; &lt;span class="o"&gt;=&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;hasResults&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&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;tableNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;hasResults&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&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;searchInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;Limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&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;startTableName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;searchInput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ExclusiveStartTableName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;startTableName&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;command&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;ListTablesCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchInput&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;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&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;TableNames&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&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;TableNames&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;startTableName&lt;/span&gt; &lt;span class="o"&gt;=&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;TableNames&lt;/span&gt;&lt;span class="p"&gt;[&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;TableNames&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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="nx"&gt;tableNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;tableNames&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&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;TableNames&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="nx"&gt;hasResults&lt;/span&gt; &lt;span class="o"&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="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hasResults&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;tableNames&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;p&gt;Now that our query could be re-used, its now easier to retrieve all Dynamo DB tables from various regions inside a single AWS account. &lt;/p&gt;

&lt;h3&gt;
  
  
  Single Account Multi-region Search
&lt;/h3&gt;

&lt;p&gt;Let's try something that seeks all tables from different &lt;em&gt;active&lt;/em&gt; regions:&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getAllDynamoDBTableNamesV3&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="s2"&gt;./get-all-dynamodb-table-names.js&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;regions&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="s2"&gt;ap-northeast-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ap-northeast-2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ap-northeast-3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ap-south-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ap-southeast-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ap-southeast-2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ca-central-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eu-central-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eu-north-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eu-west-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eu-west-2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eu-west-3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sa-east-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;us-east-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;us-east-2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;us-west-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;us-west-2&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;accountTables&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;regions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reduce&lt;/span&gt;&lt;span class="p"&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;memo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;region&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;regionTables&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;getAllDynamoDBTableNamesV3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-poc-profile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;region&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;regionTablePair&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;regionTables&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;tableName&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;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;region&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;tableName&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;regionTablePair&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;accountTables&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which should result to the following table-region key pairs:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; 
     &lt;/span&gt;&lt;span class="err"&gt;region:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'ap-southeast&lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="err"&gt;tableName:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'dynamodb-table-a'&lt;/span&gt;&lt;span class="w"&gt; 
   &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; 
     &lt;/span&gt;&lt;span class="err"&gt;region:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'ap-southeast&lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="err"&gt;tableName:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'dynamodb-table-b'&lt;/span&gt;&lt;span class="w"&gt; 
   &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; 
     &lt;/span&gt;&lt;span class="err"&gt;region:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'ap-southeast&lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="err"&gt;tableName:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'dynamodb-table-c'&lt;/span&gt;&lt;span class="w"&gt; 
   &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; 
     &lt;/span&gt;&lt;span class="err"&gt;region:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'ap-southeast&lt;/span&gt;&lt;span class="mi"&gt;-2&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="err"&gt;tableName:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'dynamodb-table-d'&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;h2&gt;
  
  
  How about multi-account query for all DynamoDBs in an AWS organization?
&lt;/h2&gt;

&lt;p&gt;Well, I'll be leaving that for you to enjoy a bit of coding using ES6 and AWS SDK v3. To give a bit of hint, you can wrap the single AWS account query into its own module and make the profile name "Configurable" so that you can implement an parallelised search across various AWS accounts.&lt;/p&gt;

&lt;p&gt;This approach should be helpful in monitoring several accounts in an entire organization.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>AWS SAM Multi-Destination Connectors</title>
      <dc:creator>Allan Chua</dc:creator>
      <pubDate>Fri, 03 Mar 2023 17:21:43 +0000</pubDate>
      <link>https://forem.com/aws-builders/aws-sam-multi-destination-connectors-5b6h</link>
      <guid>https://forem.com/aws-builders/aws-sam-multi-destination-connectors-5b6h</guid>
      <description>&lt;p&gt;&lt;em&gt;The AWS SAM CLI team has &lt;a href="https://aws.amazon.com/about-aws/whats-new/2023/02/aws-sam-connectors-multiple-destinations/"&gt;published&lt;/a&gt; a new feature for SAM connectors called multi-destination connector. This makes it easier to define multiple integrations to several AWS services on the same invoking resource (Source). Its primary goal is to reduce the complexities associated with maintaining and writing IAM permissions inside SAM templates.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In this article, we will be exploring:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What challenges do SAM connectors try to address.&lt;/li&gt;
&lt;li&gt;How to define SAM multi-destination connectors.&lt;/li&gt;
&lt;li&gt;How they improve developer experience compared to policy templates and the original variant of SAM connectors.&lt;/li&gt;
&lt;li&gt;Some opportunities that SAM team have to improve this current version.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  A little bit of context
&lt;/h2&gt;

&lt;p&gt;A few months ago, SAM connectors were introduced with the following goals in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simplifying the definition of IAM permissions:&lt;/strong&gt; With SAM connectors, developers can define IAM permissions more easily and in a more granular way.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reducing complexity in writing and maintaining serverless applications:&lt;/strong&gt; SAM connectors provide an abstraction layer that makes it easier to write and maintain serverless applications. They help to simplify the process of integrating multiple AWS services and reduce the need for writing complex IAM code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improving productivity:&lt;/strong&gt; By simplifying the definition of IAM permissions and reducing the complexity of writing custom IAM code. This directly results to improved productivity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, some &lt;a href="https://towardsaws.com/an-opinionated-view-of-aws-sam-connectors-844bdd8f96fa"&gt;improvement opportunities&lt;/a&gt; were &lt;a href="https://medium.com/@jeremydaly/getting-abstractions-wrong-with-aws-sam-serverless-connectors-e13e8c9a51a6"&gt;spotted &lt;/a&gt; by the developer community which included:&lt;/p&gt;

&lt;h3&gt;
  
  
  One connector for each source to destination pair.
&lt;/h3&gt;

&lt;p&gt;The first version of SAM connector requires a single connector definition between a source and destination pair. Take the code example below which includes three dynamo db definitions, a lambda function and three SAM connectors:&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;Transform&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless-2016-10-31&lt;/span&gt;

&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;UsersTable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless::SimpleTable&lt;/span&gt;

  &lt;span class="na"&gt;GroupsTable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless::SimpleTable&lt;/span&gt;

  &lt;span class="na"&gt;PoliciesTable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless::SimpleTable&lt;/span&gt;

  &lt;span class="c1"&gt;#&lt;/span&gt;
  &lt;span class="c1"&gt;# PUT Function&lt;/span&gt;
  &lt;span class="c1"&gt;#&lt;/span&gt;
  &lt;span class="na"&gt;PutFunction&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless::Function&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nodejs18.x&lt;/span&gt;
      &lt;span class="na"&gt;Handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;index.handler&lt;/span&gt;
      &lt;span class="na"&gt;CodeUri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;put-endpoint/&lt;/span&gt;
      &lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;USERS_TABLE_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;UsersTable&lt;/span&gt;
          &lt;span class="na"&gt;GROUPS_TABLE_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;GroupsTable&lt;/span&gt;
          &lt;span class="na"&gt;POLICIES_TABLE_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;PoliciesTable&lt;/span&gt;
      &lt;span class="na"&gt;Events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;PutResource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Api"&lt;/span&gt;
          &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;Path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/user/put"&lt;/span&gt;
            &lt;span class="na"&gt;Method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PUT"&lt;/span&gt;

  &lt;span class="c1"&gt;# First connector seems tolerable&lt;/span&gt;
  &lt;span class="na"&gt;PutUserToUserDBConnector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless::Connector&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PutFunction&lt;/span&gt;
      &lt;span class="na"&gt;Destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;UsersTable&lt;/span&gt;
      &lt;span class="na"&gt;Permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Write&lt;/span&gt;

  &lt;span class="c1"&gt;# Until you need another one! &lt;/span&gt;
  &lt;span class="c1"&gt;# (Shout out to multi-table design users)&lt;/span&gt;
  &lt;span class="na"&gt;PutUserToPolicyDBConnector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless::Connector&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PutFunction&lt;/span&gt;
      &lt;span class="na"&gt;Destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PoliciesTable&lt;/span&gt;
      &lt;span class="na"&gt;Permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Write&lt;/span&gt;

  &lt;span class="c1"&gt;# And yet another one&lt;/span&gt;
  &lt;span class="na"&gt;PutUserToGroupDBConnector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless::Connector&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PutFunction&lt;/span&gt;
      &lt;span class="na"&gt;Destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GroupsTable&lt;/span&gt;
      &lt;span class="na"&gt;Permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Write&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;With SAM multi-destination connectors, all connectors can now be grouped within their respective main resource (Original source / lambda function):&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;PutFunction&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless::Function&lt;/span&gt;
    &lt;span class="na"&gt;Connectors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="na"&gt;RWAccessConnector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;Destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;UsersTable&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PoliciesTable&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GroupsTable&lt;/span&gt;
          &lt;span class="na"&gt;Permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Write&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;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nodejs18.x&lt;/span&gt;
      &lt;span class="na"&gt;Handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;index.handler&lt;/span&gt;
      &lt;span class="na"&gt;CodeUri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;put-endpoint/&lt;/span&gt;
      &lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;USERS_TABLE_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;UsersTable&lt;/span&gt;
          &lt;span class="na"&gt;GROUPS_TABLE_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;GroupsTable&lt;/span&gt;
          &lt;span class="na"&gt;POLICIES_TABLE_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;PoliciesTable&lt;/span&gt;
      &lt;span class="na"&gt;Events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;PutResource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Api"&lt;/span&gt;
          &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;Path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/user/put"&lt;/span&gt;
            &lt;span class="na"&gt;Method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PUT"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  More lines of code compared to Sam Policy Templates
&lt;/h3&gt;

&lt;p&gt;When the first version was released, it required us to write more lines of code (9 lines for read or write connector, 10 for read and write connector) than what SAM policy templates require us to write (3 lines).&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;PutUserToGroupDBConnector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless::Connector&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PutFunction&lt;/span&gt;
      &lt;span class="na"&gt;Destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GroupsTable&lt;/span&gt;
      &lt;span class="na"&gt;Permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Write&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Read&lt;/span&gt;

  &lt;span class="c1"&gt;# What it was trying to beat prior to multi-destination connector&lt;/span&gt;
  &lt;span class="na"&gt;PutUserToGroupDBConnector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless::Connector&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Policies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;DynamoDBCrudPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;TableName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;GroupsTable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thanks to AWS SAM connectors, the overhead code of the function scaffold can now be seen as a valuable investment. As you link more resources to the main resource, the code line savings you get from using SAM connectors scales up, resulting in increased efficiency and reduced development time.&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;Connectors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="na"&gt;RWAccessConnector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;Destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;UsersTable&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PoliciesTable&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GroupsTable&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;UserIdentificationCardBucket&lt;/span&gt; &lt;span class="c1"&gt;# S3&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PaymentSettlementQueue&lt;/span&gt; &lt;span class="c1"&gt;# SQS&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;InvoicingTopic&lt;/span&gt; &lt;span class="c1"&gt;# SNS (Diverse resource definition on unified syntax)&lt;/span&gt;
          &lt;span class="na"&gt;Permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Write&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Read&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another important advantage of AWS SAM connectors is their ability to support multiple types of destination resources using a single definition tree. This feature makes SAM connectors much more user-friendly compared to SAM policy templates. &lt;/p&gt;

&lt;p&gt;With SAM connectors, there is no need to remember the specific property names (TableName, BucketName, QueueName, etc.) needed to link different resources, as the new syntax allows for a simplified and intuitive approach to defining resource connections&lt;/p&gt;

&lt;h3&gt;
  
  
  When multiple source-destination connectors are defined in separate areas of a large SAM file, it can be difficult to maintain and use them effectively.
&lt;/h3&gt;

&lt;p&gt;Prior to the release of multi-destination connectors, if engineers incrementally link several resources to a function using SAM connectors, chances that they'd do it on different sections of a large SAM file are high. &lt;/p&gt;

&lt;p&gt;Imagine engineers merging conflicting changes on a large SAM file? Sound familiar eh?&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;PutUserToUserDBConnector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless::Connector&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PutFunction&lt;/span&gt;
      &lt;span class="na"&gt;Destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;UsersTable&lt;/span&gt;
      &lt;span class="na"&gt;Permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Write&lt;/span&gt;

  &lt;span class="c1"&gt;# Imagine 200 lines in-between here&lt;/span&gt;

  &lt;span class="na"&gt;PutUserToPolicyDBConnector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless::Connector&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PutFunction&lt;/span&gt;
      &lt;span class="na"&gt;Destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PoliciesTable&lt;/span&gt;
      &lt;span class="na"&gt;Permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Write&lt;/span&gt;

  &lt;span class="c1"&gt;# Imagine 1,532 lines in-between here&lt;/span&gt;

  &lt;span class="na"&gt;PutUserToGroupDBConnector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless::Connector&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PutFunction&lt;/span&gt;
      &lt;span class="na"&gt;Destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GroupsTable&lt;/span&gt;
      &lt;span class="na"&gt;Permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Write&lt;/span&gt;

  &lt;span class="c1"&gt;# At this point, we can't remember &lt;/span&gt;
  &lt;span class="c1"&gt;# where they link and what is their purpose don't we?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unwanted incidents resulting from scattered resource definitions can lead to challenges in code reading for team members over the long run. To avoid these issues, it is important to establish proper standards and quality gates in the development process.&lt;/p&gt;

&lt;p&gt;Multi-destination connectors provide a convenient solution for managing destination-specific integration code by allowing developers to place all the code inside a unified YAML node (Source Resource). &lt;/p&gt;

&lt;p&gt;This not only streamlines the development process, but also allows for greater ease of use and more efficient resource management, making it easier to be kind to our future selves.&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;PutFunction&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless::Function&lt;/span&gt;
    &lt;span class="na"&gt;Connectors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="na"&gt;RWAccessConnector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;Destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;UsersTable&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PoliciesTable&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GroupsTable&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;UserIdentificationCardBucket&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PaymentSettlementQueue&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;InvoicingTopic&lt;/span&gt; 
          &lt;span class="na"&gt;Permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Write&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Read&lt;/span&gt;
   &lt;span class="c1"&gt;# Code trimmed for brevity&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What features can SAM CLI team still improve?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Although SAM connectors offer support for a wide range of resources, they still do not cover all the resources that are available in SAM Policy Templates. It would be particularly beneficial to have connectors that support AWS Secrets Manager and AWS SSM Parameter Store, as these are two of the most commonly used features when building integrations with non-AWS resources in serverless stacks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In my humble opinion, there is still room for improvement in SAM connectors. By implementing a more concise syntax, we can reduce the amount of boilerplate code required. For example, the following syntax could be used to define multiple connectors for a single function&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="na"&gt;PutFunction&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless::Function&lt;/span&gt;
    &lt;span class="na"&gt;WriteConnectors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SampleTableA&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SampleTableB&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Arn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;arn:aws:secretsmanager:::secret:sample-credential-Lw92LOwe&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would make it easier to manage multiple connectors and simplify the development process even further.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It would be really cool if the SAM CLI team could introduce a linting rule that enforces the usage of multi-destination connectors over 1-1 destination source pairs. This would encourage developers to adopt the more efficient and streamlined approach offered by multi-destination connectors, leading to more consistent code and better resource management.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Using SAM Multi-destination connectors can improve the readability and maintainability of large SAM templates, making it easier to manage integrations between resources.&lt;/li&gt;
&lt;li&gt;SAM Multi-destination connectors reduce integration code length, leading to more efficient code and faster development times.&lt;/li&gt;
&lt;li&gt;SAM Multi-destination connectors group connectors by the source, leading to a more organized integration code.&lt;/li&gt;
&lt;li&gt;We are no longer constrained to use one-to-one source to destination pair connector syntax.&lt;/li&gt;
&lt;li&gt;There are still some opportunities to improve SAM connector syntax after this.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wrapping Up!
&lt;/h2&gt;

&lt;p&gt;I'm eager to hear your thoughts on AWS SAM Multi-destination connectors. What do you think could be improved, and how would you improve it if you had the chance to provide feedback to the SAM CLI team? Share your comments below!&lt;/p&gt;

&lt;h3&gt;
  
  
  Related Literature
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/aws/serverless-application-model/discussions/2996"&gt;Improving supported services for SAM connectors GITHUB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/reference-sam-connector.html"&gt;AWS SAM Connector Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/managing-permissions-connectors.html"&gt;Managing resource permissions using SAM connectors&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://towardsaws.com/an-opinionated-view-of-aws-sam-connectors-844bdd8f96fa"&gt;An opinionated view of AWS SAM Connectors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.jeremydaly.com/getting-abstractions-wrong-with-aws-sam-serverless-connectors/"&gt;Getting abstractions wrong with AWS SAM Serverless Connectors&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>serverless</category>
      <category>aws</category>
      <category>lambda</category>
      <category>cloud</category>
    </item>
    <item>
      <title>An Introduction to Feature Toggles &amp; AWS AppConfig</title>
      <dc:creator>Allan Chua</dc:creator>
      <pubDate>Fri, 15 Apr 2022 14:45:22 +0000</pubDate>
      <link>https://forem.com/aws-builders/an-introduction-to-feature-toggles-aws-appconfig-449n</link>
      <guid>https://forem.com/aws-builders/an-introduction-to-feature-toggles-aws-appconfig-449n</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Rollout changes with confidence using feature toggles.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This article’s goal is to explain feature toggles and how engineering teams can benefit from using them. It will also provide a brief introduction about AWS AppConfig and how it could be used to create and manage configuration &amp;amp; feature toggles dynamically during runtime.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feature Toggling
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LcN67xri--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5jhq9ddz809yby8gcmbq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LcN67xri--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5jhq9ddz809yby8gcmbq.png" alt="Image description" width="700" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feature Toggles (aka Feature Flags) are used by engineering teams to dynamically enable/disable software behavior during runtime. This empowers them to continuously deploy an entire application stack which could include untested, upcoming, or features subjected for evaluation in production without actually releasing them to their consumers.&lt;/p&gt;

&lt;p&gt;Feature toggles greatly contributes to reducing the risk of application-level failures &amp;amp; downtimes when new software features are rolled out to production environments. This is achieved through the dynamic enabling/disabling (Toggling) of software features during runtime using intuitive configuration management tools like AWS AppConfig.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RWVzFwpI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o9rh5bq2a2eqdpnwbp03.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RWVzFwpI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o9rh5bq2a2eqdpnwbp03.png" alt="Image description" width="700" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Testing features in production is might sound crazy but there are certain situations where feature testing is only meaningful inside the context of a production environment due to the nature of traffic or amount of data in this environment.&lt;/p&gt;

&lt;p&gt;To give an example, let’s say a shoe-string startup’s engineering team recently released an integration with a 3rd party provider’s API and they never had a chance to test the integration under stress inside staging environments due to the fact that they are using pay-per-use compute environments like AWS Lambda. Running a stress test certainly results to a sudden surge of bill and would be considered as an inefficient use of valuable compute budget.&lt;/p&gt;

&lt;p&gt;Solving the mentioned problem requires the team to avoid load testing in staging environment to ensure efficient usage of compute budget and this could be achieved by testing the API integration inside a live production environment.&lt;/p&gt;

&lt;p&gt;To solve this problem in an efficient and less risky manner, feature toggles could be utilized by the team to modify the application’s behavior inside production runtime by turning on the feature toggle so the integration could be included in the normal application routine.&lt;/p&gt;

&lt;p&gt;Feature toggles enables engineering teams to observe the 3rd party API’s behavior in a live production environment and provides them the capability to disable the API integration if any throttling issues are encountered without performing a lengthy deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits
&lt;/h2&gt;

&lt;p&gt;The use-case mentioned above is just the tip of the benefit iceberg, there are several ways in which engineering teams could take advantage of feature toggles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deploy invisible features with risk mitigation in-place. This is great for software features that could only be evaluated in production environments due to either the amount of traffic or data required to evaluate their working conditions.&lt;/li&gt;
&lt;li&gt;Since engineering teams can deliver software features regardless of their validity, it would be safe for us to say that feature toggles greatly increases an engineering team’s agility.&lt;/li&gt;
&lt;li&gt;Product managers now have the capability to run A/B tests on production without the need for complex traffic segmentation tools that often makes the production applications bloated.&lt;/li&gt;
&lt;li&gt;Engineering teams can work on a single branch and push all code regardless if they are working or not which greatly increases an engineering team’s speed in delivering software features in production environments.&lt;/li&gt;
&lt;li&gt;Feature toggles offer flexibility to engineering teams by providing them means of testing assumptions that couldn’t be easily proven in development environments.&lt;/li&gt;
&lt;li&gt;Modify mobile application behaviors without resubmitting new app store and play store builds. We all know how long does it take for Apple and Google to update our mobile applications which adds another layer of complexity in testing / evaluating ideas against customer behaviors.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Use-cases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Deploy applications that requires easy customization for different countries/locales using a central code-base. This is super convenient for large multi national companies who need to design applications for different regulations and cultures of their target markets.&lt;/li&gt;
&lt;li&gt;Enable / disable new features based on customer reactions and collected insights.&lt;/li&gt;
&lt;li&gt;Swap out different machine learning models or alter their configurations based on observed performance in actual production environments and inferencing results they produce.&lt;/li&gt;
&lt;li&gt;Enable/disable integration with 3rd party capabilities like Emails, SMSs, crypto wallets, analytical APIs, web hooks, etc.
Dark launching of new business capabilities. (Dark launching is the capability to deploy software features without immediate unveiling them to customers)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This are the few ones that I could think of as we speak, I would be more interested in hearing your ideas and would love to have a chat with you guys in the comments section about your thoughts regarding feature toggles.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feature Toggling Services
&lt;/h2&gt;

&lt;p&gt;Feature toggling services like AWS AppConfig offers benefits that hard-coded configuration / JSON files or open source tools can’t offer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Central management of feature flags inside easy to use GUIs.&lt;/li&gt;
&lt;li&gt;Instant switching of features during runtime.&lt;/li&gt;
&lt;li&gt;Eliminates the need to worry about the stability, continuity and sustainability of an open-source project.&lt;/li&gt;
&lt;li&gt;Focus engineering efforts towards building differentiating capabilities over developing feature toggling capabilities.&lt;/li&gt;
&lt;li&gt;You get to audit usage data of feature toggles without building analytical capabilities on your own.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  AWS AppConfig
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xphKi8Zu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sgo0tyxitb6lpzq6f5vz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xphKi8Zu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sgo0tyxitb6lpzq6f5vz.png" alt="AWS AppConfig Dashboard" width="700" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AppConfig is a service offered by AWS for the purpose of centralizing management of configuration data. It helps us store feature flag values and other configuration data so we don’t have to embed configuration data inside our codebases or build our own feature flag management tools.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TGPG2P4l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ahgmmxl1bx5zkqsidqiw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TGPG2P4l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ahgmmxl1bx5zkqsidqiw.png" alt="Application and Environment Constructs" width="700" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AWS AppConfig also includes the capability to group related configuration through the use of &lt;a href="https://docs.aws.amazon.com/appconfig/2019-10-09/APIReference/API_Application.html"&gt;application &lt;/a&gt; &amp;amp; &lt;a href="https://docs.aws.amazon.com/appconfig/2019-10-09/APIReference/API_Environment.html"&gt;environment&lt;/a&gt; constructs which makes configuration management simpler.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xaTyx4gI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/008likazi5bk452jrcjd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xaTyx4gI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/008likazi5bk452jrcjd.png" alt="Sample ML Inferencing Configuration" width="700" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AWS AppConfig comes with configuration validators that acts as an additional set of safety measures geared towards reducing the number of configuration errors originating from invalid and faulty values.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jFo6843C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vpveibbtcdiqfd8vjd3p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jFo6843C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vpveibbtcdiqfd8vjd3p.png" alt="Deployment tool" width="692" height="697"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The service also comes with ready-to-use deployment tool that streamlines the management of feature flags during application runtime. This tool includes several deployment strategies which makes AWS AppConfig shine better compared to other feature toggling tools out there.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3hKcwBOO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d2131bjavkuvacmlr5va.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3hKcwBOO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d2131bjavkuvacmlr5va.png" alt="Deployment Strategies" width="700" height="152"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It also includes a monitoring tool integrated to AWS CloudWatch that we could use to monitor and observe the impact of feature toggles without exerting too much effort.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---BMr8oIW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bmy3xd4arp8gq8nllb1v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---BMr8oIW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bmy3xd4arp8gq8nllb1v.png" alt="Monitoring via CloudWatch Alarms" width="700" height="150"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AWS AppConfig is compatible with applications hosted on EC2, AWS Lambda, container services, mobile applications or IOT devices.&lt;/p&gt;

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

&lt;p&gt;Feature toggles enable software engineering teams to enable/disable new software features. It empowers product owners too by providing the capability to test out assumptions and ideas without taking the risk of annoying customers in production environments. AWS AppConfig is an awesome tool that AWS customers could use to get started with feature toggling.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stay tune for more AWS AppConfig articles
&lt;/h2&gt;

&lt;p&gt;I’m currently working on a few more articles aimed at helping developers in provisioning, testing and integrating AWS AppConfig on different layers of serverless applications. If you have any use-cases that you’d like to try using AWS AppConfig, feel free to drop a comment here and let’s see how could we collaborate together to implement a proof of concept with other AWS community builders.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Learning
&lt;/h2&gt;

&lt;p&gt;Here are some articles and videos that everybody could use to learn more about AWS AppConfig.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AppConfig User Guide &lt;a href="https://docs.aws.amazon.com/appconfig/latest/userguide/what-is-appconfig.html"&gt;[Link]&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;AppConfig API Reference &lt;a href="https://docs.aws.amazon.com/appconfig/2019-10-09/APIReference/Welcome.html"&gt;[Link]&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;AppConfig Introduction Video &lt;a href="https://www.youtube.com/watch?v=rL_e6W6SlMM"&gt;[Link]&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;AppConfig Getting Started Video &lt;a href="https://www.youtube.com/watch?v=ztIxMY3IIu0"&gt;[Link]&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>appconfig</category>
      <category>config</category>
      <category>featuretoggles</category>
    </item>
  </channel>
</rss>
