<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Adriano Sastre Vieira</title>
    <description>The latest articles on DEV Community by Adriano Sastre Vieira (@adrianosastre).</description>
    <link>https://dev.to/adrianosastre</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%2F782524%2Fbbf76bdf-6931-40d4-9000-702f0a1ef4b4.jpeg</url>
      <title>DEV Community: Adriano Sastre Vieira</title>
      <link>https://dev.to/adrianosastre</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/adrianosastre"/>
    <language>en</language>
    <item>
      <title>Configuring Docker without Docker Desktop on Windows / WSL2</title>
      <dc:creator>Adriano Sastre Vieira</dc:creator>
      <pubDate>Sun, 13 Feb 2022 14:24:08 +0000</pubDate>
      <link>https://dev.to/adrianosastre/configuring-docker-without-docker-desktop-on-windows-wsl2-45mc</link>
      <guid>https://dev.to/adrianosastre/configuring-docker-without-docker-desktop-on-windows-wsl2-45mc</guid>
      <description>&lt;p&gt;Hello,&lt;/p&gt;

&lt;p&gt;Since February 1st, 2022 &lt;strong&gt;Docker Desktop&lt;/strong&gt; is not free anymore for companies that have more than 250 employees or more than $10 million in annual revenue: &lt;a href="https://www.docker.com/pricing/faq"&gt;Docker FAQs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But, as stated in the above link, it is still possible to use only Docker CLI and Engine for free: &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Can I just install the Docker CLI instead of using Docker Desktop?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you use a Mac, you can install Docker CLI and Engine inside a virtual machine, using VirtualBox or VMware Fusion for example, which may require purchasing a license for VirtualBox or VMware Fusion. On Windows you could install and run Docker CLI and Engine inside WSL2. If you use a Linux machine you can easily use the Docker CLI and Docker Engine, See the documentation on installing Docker Engine for instructions. Docker Desktop is not yet available for Linux.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This post purpose is provide a step-by-step to still run Docker commands on &lt;strong&gt;Windows&lt;/strong&gt; via &lt;strong&gt;WSL2&lt;/strong&gt;, after uninstalling Docker Desktop. For that, we're going to use the &lt;strong&gt;Ubuntu&lt;/strong&gt; distribution.&lt;/p&gt;

&lt;p&gt;So we're going to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Uninstall Docker Desktop on Windows&lt;/li&gt;
&lt;li&gt;Configure WSL2 on Windows&lt;/li&gt;
&lt;li&gt;Install Ubuntu on Windows&lt;/li&gt;
&lt;li&gt;Install Docker CLI + Compose on Ubuntu&lt;/li&gt;
&lt;li&gt;Execute Docker commands.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  About WSL and WSL2
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;WSL (Windows Sybsystem for Linux)&lt;/strong&gt; allows you to run Linux command-line tools and apps alongside your Windows command-line, desktop and store apps, and to access your Windows files from within Linux. This enables you to use Windows apps and Linux command-line tools on the same set of files if you wish.&lt;/p&gt;

&lt;p&gt;WSL2 is a new version of the WSL architecture that powers it to run ELF64 Linux binaries on Windows. Its primary goals are to increase file system performance, as well as adding full system call compatibility.&lt;/p&gt;

&lt;h1&gt;
  
  
  Uninstalling Docker Desktop on Windows
&lt;/h1&gt;

&lt;p&gt;If installed, uninstall Docker Desktop on Windows via Control Panel - Programs and Features - Uninstall.&lt;/p&gt;

&lt;p&gt;That will make docker commands stop working on Windows.&lt;/p&gt;

&lt;h1&gt;
  
  
  Enabling WSL on Windows
&lt;/h1&gt;

&lt;p&gt;In order to enable WSL on Windows, execute the following commands in &lt;strong&gt;PowerShell&lt;/strong&gt; running in &lt;strong&gt;admin mode&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart

dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open PowerShell again and run the wsl command. If it does not work, restart your PC.&lt;/p&gt;

&lt;h1&gt;
  
  
  Configuring WSL2
&lt;/h1&gt;

&lt;p&gt;Download the WSL2 kernel via: &lt;a href="https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi"&gt;https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Execute the downloaded &lt;strong&gt;wsl_update_x64.msi&lt;/strong&gt; file.&lt;/p&gt;

&lt;p&gt;WSL version 1 is the default, it's important to change to version 2, so all Linux installed distros will be v2 by default. &lt;/p&gt;

&lt;p&gt;In order to do that, execute the following command in &lt;strong&gt;PowerShell&lt;/strong&gt; running in &lt;strong&gt;admin mode&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wsl --set-default-version 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Limiting WSL2 resources (optional)
&lt;/h1&gt;

&lt;p&gt;If you want to limit WSL2 resources, create a file named &lt;strong&gt;.wslconfig&lt;/strong&gt; in you user root folder on Windows (C:\Users&amp;lt;your_username&amp;gt;) and define the configurations, e.g.:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[wsl2]
memory=8GB
processors=4
swap=2GB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Installing Ubuntu on Windows
&lt;/h1&gt;

&lt;p&gt;In the &lt;strong&gt;Windows Store&lt;/strong&gt; app, choose the &lt;strong&gt;Ubuntu&lt;/strong&gt; Linux distribution and download/install it. &lt;/p&gt;

&lt;p&gt;After that, your &lt;strong&gt;WSL2 / Ubuntu&lt;/strong&gt; is already working. &lt;/p&gt;

&lt;p&gt;You can enter the &lt;strong&gt;Ubuntu&lt;/strong&gt; terminal from the Windows start menu. &lt;/p&gt;

&lt;p&gt;The first time Ubuntu is run, it's necessary to define an username. Uou can use the same Windows username and password. This will be the *&lt;em&gt;root *&lt;/em&gt; user of you WSL2 instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Updating Ubuntu:
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Important: All commands from this point on are performed in the Ubuntu terminal.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo apt-get update

$ sudo apt-get upgrade -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Installing Docker Engine
&lt;/h1&gt;

&lt;p&gt;Run the following commands in order to install the Docker Engine on the WSL2 Ubuntu instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"
$ sudo apt install apt-transport-https ca-certificates curl net-tools software-properties-common -y
$ sudo apt-get update
$ apt-cache policy docker-ce
$ sudo apt install docker-ce -y

$ sudo usermod -aG docker &amp;lt;incluir aqui o seu usuário do Ubuntu&amp;gt;

$ sudo service docker start

$ service docker status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Installing Docker Compose
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
$ sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

$ docker-compose --version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Executing Docker on Ubuntu
&lt;/h1&gt;

&lt;p&gt;From now on, you may execute docker and/or docker-compose commands at will via the Ubuntu terminal. &lt;/p&gt;

&lt;p&gt;So suppose you were used to go to the Windows directory "C:\my-project" and run docker commands from there; now via the Ubuntu terminal, you still can go to any Windows directory, which are mounted under the /mnt directory, and run the docker commands. &lt;/p&gt;

&lt;p&gt;E.g. in this case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cd /mnt/c/my-project

$ docker ....

$ docker-compose ....
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Installing other tools and dependencies
&lt;/h1&gt;

&lt;p&gt;Depending on your use case, you may need to install other tools and dependencies on the WSL2 Ubuntu instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Node.js and NPM (optional)
&lt;/h2&gt;

&lt;p&gt;As it is very common, this section covers the Node.js / NPM installation on Ubuntu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo apt install nodejs
$ curl -sL https://deb.nodesource.com/setup_14.x | sudo bash -
$ sudo apt -y install nodejs

$ node -v

$ sudo apt install npm

$ sudo npm cache clean -f
$ sudo npm install -g n
$ sudo n stable
$ sudo npm install -g npm@latest

$ npm -v
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  ---
&lt;/h1&gt;

&lt;p&gt;That's it! Thanks for reading.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adriano Sastre Vieira&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>wsl</category>
      <category>wsl2</category>
      <category>ubuntu</category>
    </item>
    <item>
      <title>React basic CRUD app with Firebase Realtime Database - Hands-on</title>
      <dc:creator>Adriano Sastre Vieira</dc:creator>
      <pubDate>Mon, 17 Jan 2022 10:31:42 +0000</pubDate>
      <link>https://dev.to/adrianosastre/crud-react-basic-app-with-firebase-realtime-database-hands-on-15hh</link>
      <guid>https://dev.to/adrianosastre/crud-react-basic-app-with-firebase-realtime-database-hands-on-15hh</guid>
      <description>&lt;p&gt;Hi, I'm Adriano Sastre Vieira, software developer. &lt;/p&gt;

&lt;p&gt;Today we're gonna build a basic React app, that connects to an API and perform the basic CRUD operations: POST, GET, PUT, DELETE. &lt;/p&gt;

&lt;p&gt;I assume you have Node / npm / React installed and configured on your machine.&lt;/p&gt;

&lt;h1&gt;
  
  
  Google Firebase Realtime Database
&lt;/h1&gt;

&lt;p&gt;As this is a CRUD POC, in order to run this project successfully, we need to have an API that provides the CRUD operations. Google Firebase is real handy to help us with that.&lt;/p&gt;

&lt;p&gt;In order to configure it, please login to &lt;a href="https://firebase.google.com"&gt;https://firebase.google.com&lt;/a&gt; (create the GCP account if you don't have one) and go to Console at &lt;a href="https://console.firebase.google.com/"&gt;https://console.firebase.google.com/&lt;/a&gt;. After that, follow these simple steps:&lt;/p&gt;

&lt;p&gt;1 - Create a Project&lt;br&gt;
2 - Create a Realtime Database (don't forget to select "Init on test mode" so you have access to the APIs)&lt;/p&gt;

&lt;p&gt;Et voilà, you have a realtime database URL that looks like "https://--default-rtdb.firebaseio.com/" and it is super powerful, in summary realtime database is a serverless no-sql database that already provides and API with all CRUD operations (POST, GET, PUT, PATCH, DELETE) on the fly!&lt;/p&gt;

&lt;h1&gt;
  
  
  About React - A brief summary
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;React&lt;/strong&gt;, a "&lt;strong&gt;Javascript library for User Interfaces&lt;/strong&gt;", is a very popular free and open source library, and it allows developers to organize the way we use modern javascript to make the glue between HTML and CSS. &lt;/p&gt;

&lt;p&gt;It allow us to build "Single Page Applications", aka &lt;strong&gt;SPA&lt;/strong&gt;, giving the web app a more fluid, "reactive" look and feel, similar to mobile native apps. In other words, no more request, loading, response during the user experience on the web.&lt;/p&gt;

&lt;p&gt;Once the team learn React, we are more productive and produce less error-prone code, by not using a javascript imperative approach, but declarative approach instead (e.g. instead of document.querySelector(‘button’)… we add extra attributes onClick to a button pointing to a function (to react to that element).&lt;/p&gt;

&lt;p&gt;It is also good to follow some &lt;strong&gt;conventions&lt;/strong&gt; (directory and files naming for example) when programming with react, as we'll see with this project.&lt;/p&gt;

&lt;p&gt;The basics of React are the &lt;strong&gt;Components&lt;/strong&gt; - the “Building blocks”, that allows us to make reusable and more easy to maintain code. Components should be focused on 1 thing only!&lt;/p&gt;

&lt;p&gt;Components files usually contains a javascript function, exported as default, and the convention is that the files and function name are the same and starts with Capital letter, and are stored under a "components" folder (subfolders can be created to organize the project).&lt;/p&gt;

&lt;p&gt;The components functions have the &lt;strong&gt;props&lt;/strong&gt; attribute, that helps enabling dynamic content. props.children is useful on wrapping components.&lt;/p&gt;

&lt;p&gt;The components functions returns &lt;strong&gt;JSX&lt;/strong&gt; code - similar to html code, but its attributes are from plain javascript and not html, e.g.: className instead of class. On JSX code we can use curly braces ({}) in order to embed single-line-expressions javascript into ‘html’ code.&lt;/p&gt;

&lt;p&gt;When it comes to &lt;strong&gt;Styling&lt;/strong&gt;, we can create a Component.module.css file and import it on the component with "import classes from ‘./Component.module.css’;" so we can use this file's &lt;strong&gt;CSS&lt;/strong&gt; classes only on the current Component.&lt;/p&gt;

&lt;p&gt;React also provides some &lt;strong&gt;hooks&lt;/strong&gt;, for example the &lt;strong&gt;useState&lt;/strong&gt; hook, very useful to make our pages more dynamic, for example while we're loading asynchronous data from an API. There are others useful hooks, like &lt;strong&gt;useEffect&lt;/strong&gt; and &lt;strong&gt;useHistory&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In order to change "pages" in our &lt;strong&gt;SPA&lt;/strong&gt; React application without using the traditional request-response way, we can use the react-router-dom lib in order to implement a &lt;strong&gt;Router&lt;/strong&gt; for our app.&lt;/p&gt;

&lt;p&gt;With a Router, even on a single page, we have the illusion that the page changes, but the app stays fast and reactive, comparing to a new request/response. Router pages are react components, but loaded by the Router, and the &lt;strong&gt;convention&lt;/strong&gt; is to save them on a ‘/pages’ folder.&lt;/p&gt;

&lt;p&gt;That's basically the things we used on this project.&lt;/p&gt;

&lt;h1&gt;
  
  
  Open project on Visual Studio Code
&lt;/h1&gt;

&lt;p&gt;This project was implemented with React 17.0.2 and javascript, and is public available on github:&lt;br&gt;
&lt;a href="https://github.com/adrianosastre/react-crud-app"&gt;https://github.com/adrianosastre/react-crud-app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please clone and open it on VS Code, and look at these important chunks of code:&lt;/p&gt;

&lt;p&gt;1 - API Endpoint configuration: &lt;/p&gt;

&lt;p&gt;Rename the ".env.example" file to ".env" and configure the REACT_APP_API_URL key to your created realtime database URL.&lt;/p&gt;

&lt;p&gt;2 - This Project structure:&lt;/p&gt;

&lt;p&gt;This React CRUD project was created with the "npx create-react-app" command, and cleaned so only files that matters for this article was maintained. &lt;/p&gt;

&lt;p&gt;Currently, it contains the basics for using React, and you can navigate the project noticing the following:&lt;/p&gt;

&lt;p&gt;a. The project organization (folders, names convention)&lt;br&gt;
b. The use of Routing (react-router-dom)&lt;br&gt;
c. The components (how to pass values to children and parents components; wrapper components...)&lt;br&gt;
d. The use of JSX on the components&lt;br&gt;
e. Basic CSS styling, flex layout&lt;br&gt;
f. React states and other main hooks&lt;br&gt;
g. Interacting to the realtime database API data by using the fetch javascript API.&lt;/p&gt;

&lt;h1&gt;
  
  
  Run!
&lt;/h1&gt;

&lt;p&gt;Run you project with the "npm run start" command and enjoy!&lt;/p&gt;

&lt;p&gt;The project CRUD are "Things", so the first time the "Things List" is clicked you see an empty list (that makes sense because your realtime database is empty):&lt;/p&gt;

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

&lt;p&gt;Click on the "Add Thing" link, fill in the form and click on the "Add Thing" button:&lt;/p&gt;

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

&lt;p&gt;Once the "think" item is created, the app goes to the things list page:&lt;/p&gt;

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

&lt;p&gt;Click on the card to view its details:&lt;/p&gt;

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

&lt;p&gt;From the details page you can edit or delete the thing item.&lt;/p&gt;

&lt;h1&gt;
  
  
  That's it!
&lt;/h1&gt;

&lt;p&gt;Thanks, I hope this was helpful, and I'm available for any comments or questions here or via &lt;a href="mailto:adrianosastre@gmail.com"&gt;adrianosastre@gmail.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>cloud</category>
      <category>crud</category>
      <category>javascript</category>
    </item>
    <item>
      <title>AWS Serverless and the DynamoDB Single Table Design - Hands-on with CDK v2</title>
      <dc:creator>Adriano Sastre Vieira</dc:creator>
      <pubDate>Thu, 30 Dec 2021 00:25:12 +0000</pubDate>
      <link>https://dev.to/adrianosastre/aws-serverless-and-the-dynamodb-single-table-design-hands-on-with-cdk-v2-38d0</link>
      <guid>https://dev.to/adrianosastre/aws-serverless-and-the-dynamodb-single-table-design-hands-on-with-cdk-v2-38d0</guid>
      <description>&lt;p&gt;Hi, I'm Adriano Sastre Vieira, software developer at Inatel Competence Center. &lt;/p&gt;

&lt;p&gt;In this article I'll talk about &lt;strong&gt;AWS Serverless&lt;/strong&gt;, also called &lt;strong&gt;managed services&lt;/strong&gt; (because you don't have to manage a server in order to deploy these services), with more focus on &lt;strong&gt;DynamoDB&lt;/strong&gt; and the &lt;strong&gt;Single Table Design&lt;/strong&gt; concept.&lt;/p&gt;

&lt;p&gt;Not recommended, but click here if you want to skip the theory and go strait to the hands on.&lt;/p&gt;

&lt;h1&gt;
  
  
  Serverless!
&lt;/h1&gt;

&lt;p&gt;DynamoDB is a AWS managed database service. When we talk about AWS managed service, we're also talking about Serverless.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Serverless&lt;/strong&gt; is the practice of using managed services with event driven compute functions to avoid or minimize infrastructure management, configuration, operations, and idle capacity.&lt;/p&gt;

&lt;p&gt;But it's not just about computing, there is a wide range of things an application architecture may need, e.g. Compute, Storage, Data, Monitoring, Queue, Notification ...&lt;/p&gt;

&lt;p&gt;So, it is correct to say that &lt;strong&gt;DynamoDB&lt;/strong&gt; is a serverless database, or more specifically, an AWS managed database service.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Serverless&lt;/strong&gt; is a big paradigm shift, potentially even more impactful than the move to the &lt;strong&gt;Cloud&lt;/strong&gt; before it!&lt;/p&gt;

&lt;p&gt;Check the articles below if you want to go deeper into Serverless:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://medium.com/serverless-transformation/in-defence-of-serverless-the-term-764514653ea7" rel="noopener noreferrer"&gt;In defense of “Serverless” — the term&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pauldjohnston.medium.com/serverless-best-practices-b3c97d551535" rel="noopener noreferrer"&gt;Serverless Best Practices&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Microservices
&lt;/h1&gt;

&lt;p&gt;Yet on the related concepts, we have the &lt;strong&gt;Microservices&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;The microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. &lt;/p&gt;

&lt;p&gt;These services are built around business capabilities and independently deployable by fully automated deployment machinery. &lt;/p&gt;

&lt;p&gt;Many people are using Serverless applications to build a microservice architecture!&lt;/p&gt;

&lt;p&gt;I believe this is the number one article for those who wants to go deeper on &lt;a href="https://martinfowler.com/articles/microservices.html" rel="noopener noreferrer"&gt;Microservices&lt;/a&gt; - from Martin Fowler.&lt;/p&gt;

&lt;h1&gt;
  
  
  Serverless and the AWS Cloud
&lt;/h1&gt;

&lt;p&gt;Ok, some important things about AWS before we cut to the chase.&lt;/p&gt;

&lt;h2&gt;
  
  
  AWS - Fundamentals (The 5 Pillars, new "mental models")
&lt;/h2&gt;

&lt;p&gt;When starting working with AWS, it's normal to feel quite lost, as it has about 200 services, many of them overlapping others on their responsibilities, doing similar stuff, and the AWS extensive documentation does not seem to help beginners, it's difficult to FOCUS and use what is best for each case.&lt;/p&gt;

&lt;p&gt;In addition, when we change from a monolithic architecture to micro services, it's a big shift, it's like changing from classical physics to quantum physics!&lt;/p&gt;

&lt;p&gt;So, a very good start point is to understand the &lt;strong&gt;AWS Fundamentals&lt;/strong&gt;, which talks about &lt;strong&gt;the 5 pillars&lt;/strong&gt; that requires new &lt;strong&gt;mental models&lt;/strong&gt;, and summarizes the AWS services and concepts for each one:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Operational excellence&lt;/strong&gt;: thinking about operations as automation (CloudFormation, CDK ...)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt;: zero trust, the principle of least privilege (IAM, data encryption ...)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reliability&lt;/strong&gt;: using fault isolation zones to limit blast radius (regions, quotas, throttling ...)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance Efficiency&lt;/strong&gt;: think of your services as cattle, not pets. (horizontal vs vertical scaling, auto scaling ...)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost Optimization&lt;/strong&gt;: OpEx (pay-as-you-go) instead of CapEx (one-time purchase)&lt;/li&gt;
&lt;/ul&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%2Fcxzl3febx9mnua7v92ek.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%2Fcxzl3febx9mnua7v92ek.png" alt="AWS Fundamentals"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So if you didn't yet, now it's a good opportunity to check the &lt;a href="https://aws.amazon.com/getting-started/fundamentals-core-concepts/" rel="noopener noreferrer"&gt;AWS Fundamentals&lt;/a&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  The AWS Managed Services
&lt;/h2&gt;

&lt;p&gt;When we talk about AWS managed services, these are the main ones:&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%2Fqtbz8so5ssvrhm9lit4r.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%2Fqtbz8so5ssvrhm9lit4r.png" alt="AWS Serverless"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are many pros on using managed services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cost reduction&lt;/strong&gt;: the initial cost tend to zero (free tier for most of them, after that pay as you use)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt;: e.g. no need to install security patches on servers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NoOps&lt;/strong&gt;: e.g. no servers / storage to manage or to scale, no need for a infrastructure team&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;More scalable&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;High performance&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Greener&lt;/strong&gt;: if you don't need, you're not using the server resources&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Productivity&lt;/strong&gt;: developers focus on delivering business value&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some cool links to learn more about Serverless on AWS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/serverless/" rel="noopener noreferrer"&gt;Serverless on AWS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/getting-started/deep-dive-serverless/" rel="noopener noreferrer"&gt;AWS Deep Dive Serverless&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serverlessland.com/" rel="noopener noreferrer"&gt;Serverless Land&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aws.amazon.com/free" rel="noopener noreferrer"&gt;AWS Free Tier&lt;/a&gt; - in order to check if a AWS service is free or how much it costs&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Minimum Stack: API Gateway + Lambda + DynamoDB
&lt;/h2&gt;

&lt;p&gt;While this article focus is the DynamoDB, in order to talk about it in a more practical way, it's important to think in a minimum sample architecture where it fits.&lt;/p&gt;

&lt;p&gt;The classical AWS example is: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An API (e.g. some CRUD) implemented via API Gateway;&lt;/li&gt;
&lt;li&gt;This API is accessed by a client (e.g, the Postman, or a mobile/web app);&lt;/li&gt;
&lt;li&gt;Lambda function(s) in order to manage this API and interface with the database&lt;/li&gt;
&lt;li&gt;And the DynamoDB table in order to store data.&lt;/li&gt;
&lt;/ul&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%2F8ll5gg9eb6u9xzcxjq8r.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%2F8ll5gg9eb6u9xzcxjq8r.png" alt="Minimum Stack"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'll briefly talk about API Gateway and Lambda before going to DynamoDB. Pay attention to the &lt;strong&gt;&lt;em&gt;italic&lt;/em&gt;&lt;/strong&gt; words, they are related to the &lt;strong&gt;Serverless&lt;/strong&gt; concepts.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://aws.amazon.com/api-gateway" rel="noopener noreferrer"&gt;https://aws.amazon.com/api-gateway&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fully &lt;strong&gt;&lt;em&gt;managed service&lt;/em&gt;&lt;/strong&gt; that makes it easy for developers to create, publish, maintain, monitor, and secure APIs at &lt;strong&gt;&lt;em&gt;any scale&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Handles all the tasks involved in accepting and processing up to hundreds of thousands of concurrent API calls, including traffic management, CORS support, authorization and access control, throttling, monitoring, and API version management.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lambda
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://aws.amazon.com/lambda" rel="noopener noreferrer"&gt;https://aws.amazon.com/lambda&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AWS Lambda is an &lt;strong&gt;&lt;em&gt;event-driven&lt;/em&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;em&gt;serverless computing platform&lt;/em&gt;&lt;/strong&gt; provided by Amazon as a part of Amazon Web Services. &lt;/p&gt;

&lt;p&gt;Runs code in response to events and &lt;strong&gt;&lt;em&gt;automatically manages the computing resources&lt;/em&gt;&lt;/strong&gt; required by that code.&lt;/p&gt;

&lt;p&gt;Triggered by events (e.g. HTTP Calls via API Gateway, S3 new objects on a bucket, new SQS in a queue, new item in a DynamoDB table ...)&lt;/p&gt;

&lt;h2&gt;
  
  
  DynamoDB
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://aws.amazon.com/dynamodb/" rel="noopener noreferrer"&gt;https://aws.amazon.com/dynamodb/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we're talking. DynamoDB definitions and main characteristics from AWS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;&lt;strong&gt;Fast&lt;/strong&gt;&lt;/em&gt; and &lt;strong&gt;&lt;em&gt;flexible&lt;/em&gt;&lt;/strong&gt; NoSQL database service for &lt;strong&gt;&lt;em&gt;any scale&lt;/em&gt;&lt;/strong&gt;. Key-value and document database that delivers &lt;em&gt;&lt;strong&gt;single-digit millisecond performance&lt;/strong&gt;&lt;/em&gt; at &lt;em&gt;&lt;strong&gt;any scale&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;&lt;strong&gt;Fully managed&lt;/strong&gt;&lt;/em&gt;, multi-region, multi-active, durable database with built-in security, backup and restore, and in-memory caching for &lt;strong&gt;&lt;em&gt;internet-scale&lt;/em&gt;&lt;/strong&gt; applications.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;&lt;strong&gt;Free-tier forever&lt;/strong&gt;&lt;/em&gt; applied, up to 25GB storage, 25 read/write provisioned units (about 200M requests/month). After that: cost by storage and requests.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For those who are curious about its roots, read &lt;a href="https://www.dynamodbguide.com/the-dynamo-paper" rel="noopener noreferrer"&gt;"The Dynamo Paper"&lt;/a&gt;. Summary: it was created by Amazon (2004-2007), public released by AWS in 2012.&lt;/p&gt;

&lt;h3&gt;
  
  
  DynamoDB as part of a Serverless Architecture
&lt;/h3&gt;

&lt;p&gt;When we first saw these &lt;em&gt;propaganda&lt;/em&gt;, it seems all good news alright? &lt;/p&gt;

&lt;p&gt;But wait, it is not that simple.&lt;/p&gt;

&lt;p&gt;First, adopting DynamoDB in place of a relational database is just part of moving to a Serverless Architecture, although a very important one.&lt;/p&gt;

&lt;p&gt;The idea of using NoSQL for any and all core business requirements is quite new, and this is because the whole system now works at a scale and event-driven nature before inexistent.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Bad designed DynamoDB tables has often the major impact on a serverless architectured system, both on performance and costs!&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Don't get me wrong, DynamoDB is really great when the data is properly modeled! There are lots of benefits on using it, as easily integrating it with other managed services like lambdas, really high performance and scalability, and very low initial cost.&lt;/p&gt;

&lt;p&gt;And yes, it is possible to use it correctly on the majority of the systems (remember: Amazon uses it on its shopping cart, so why can't we?); but in summary: &lt;strong&gt;DynamoDB is complex, doing it well even more so!&lt;/strong&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  DynamoDB NoSQL design vs RDBMS
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;NoSQL&lt;/strong&gt; design requires a different mindset than &lt;strong&gt;RDBMS&lt;/strong&gt; design.&lt;/p&gt;

&lt;p&gt;With RDBMS, you can go ahead and create a &lt;strong&gt;normalized&lt;/strong&gt; data model without thinking about &lt;strong&gt;access patterns&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;By contrast, you shouldn't start designing the schema for DynamoDB until you know the questions that need to be answered. &lt;strong&gt;Understanding the business problems and the application use cases up front is essential!&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To clarify, it follows some common access patterns examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get a user's profile data&lt;/li&gt;
&lt;li&gt;List the user's orders&lt;/li&gt;
&lt;li&gt;Get an order and its items&lt;/li&gt;
&lt;li&gt;List the user's orders by status&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of course, on a real system there are lots more.&lt;/p&gt;

&lt;h3&gt;
  
  
  DynamoDB design considerations
&lt;/h3&gt;

&lt;p&gt;This AWS documentation "&lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-general-nosql-design.html#bp-general-nosql-design-concepts" rel="noopener noreferrer"&gt;NoSQL Design&lt;/a&gt;" goes deeper on the concepts I've summarized in this image:&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%2Fj6m98ww7mu014bjysmjk.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%2Fj6m98ww7mu014bjysmjk.png" alt="Design considerations"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After you identify specific query requirements, you can organize data according to general principles that govern performance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Keep related data together&lt;/strong&gt;.  Keeping related data in close proximity has a major impact on cost and performance. Instead of distributing related data items across multiple tables, you should keep related items in your NoSQL system as close together as possible. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use sort order&lt;/strong&gt;.  Related items can be grouped together and queried efficiently if their key design causes them to sort together. This is an important NoSQL design strategy.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Distribute queries&lt;/strong&gt;.  It is also important that a high volume of queries not be focused on one part of the database, where they can exceed I/O capacity. Instead, you should design data keys to distribute traffic evenly across partitions as much as possible, avoiding "hot spots".&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Using indexes&lt;/strong&gt;.  By creating specific global secondary indexes, you can enable different queries than your main table can support, and that are still fast and relatively inexpensive.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;These general principles translate into some common design patterns that you can use to model data efficiently in DynamoDB.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This presentation &lt;a href="https://d1.awsstatic.com/events/reinvent/2019/REPEAT1_Advanced_design_patterns_for_Amazon_DynamoDB_DAT334-R1.pdf" rel="noopener noreferrer"&gt;Advanced Design Patterns for Amazon DynamoDB&lt;/a&gt; is great for better understanding it.&lt;/p&gt;

&lt;h3&gt;
  
  
  DynamoDB - table capacity
&lt;/h3&gt;

&lt;p&gt;Per DynamoDB table, it is possible to configure the capacity as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OnDemand&lt;/strong&gt;: automatic and "infinite" scaling;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Provisioned&lt;/strong&gt;: possible to define independent read and write unit capacities; also possible to configure auto-scaling rules, e.g. min/max scaling, how fast to scale.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is very challenging to proper configure the DynamoDB table provisioned capacity, and it can imply on requests being throttled. Totally configurable, we can set different capacity values for reading and writing requests, and we can also configure read and write scaling: from how much percent of use the table starts reacting, what is the max and minimum capacity it can have, and how much time it waits till scaling up or down. All of these configuration can be done for the table and each of its indexes.&lt;/p&gt;

&lt;p&gt;When correctly configured, a provisioned capacity leads to less costs than an on demand capacity. And certainly it is less complicated to configure and watch it for one &lt;strong&gt;single table&lt;/strong&gt; than for many tables. In addition, when configured as on demand capacity, usually the DynamoDB takes more time to understand a high I/O volume of requests and scaling. During this time, we can have requests being throttled.&lt;/p&gt;

&lt;p&gt;It is also possible to change between OnDemand and Provisioned once a day! This is very useful for scenarios where on a specific time range, it is not possible to predict the scaling at all, e.g. e-commerce system on Black Fridays.&lt;/p&gt;

&lt;h3&gt;
  
  
  DynamoDB PK, SK, Attributes
&lt;/h3&gt;

&lt;p&gt;As key-value and document database, each DynamoDB table item may have different attributes! &lt;/p&gt;

&lt;p&gt;But it is mandatory to define the primary key. In a nutshell:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Primary Key&lt;/strong&gt;:&lt;br&gt;
&lt;strong&gt;PK&lt;/strong&gt; = Partition Key (aka hash key) (mandatory)&lt;br&gt;
&lt;strong&gt;SK&lt;/strong&gt; = Sort Key (aka range key) (optional)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attributes&lt;/strong&gt;: Binary, Number or String&lt;br&gt;
Can be grouped in a JSON-like structure&lt;/p&gt;

&lt;p&gt;This image exemplifies the DynamoDB structure:&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%2F8dyk07fad0fbfjn4e494.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%2F8dyk07fad0fbfjn4e494.png" alt="DynamoDB structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And this shows an example of a populated 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%2Fpo9ujdd9hn15ds1oosud.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%2Fpo9ujdd9hn15ds1oosud.png" alt="Populated Table"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  DynamoDB - How to query data
&lt;/h3&gt;

&lt;p&gt;Querying data is normally the most important consideration when designing DynamoDB schema, as usually there are much more reading than writing operations.&lt;/p&gt;

&lt;p&gt;There are basically 3 ways of querying DynamoDB data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Get&lt;/strong&gt; = one specific item, by PK or PK/SK&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query&lt;/strong&gt; = several items, by PK/SK or indexed attributes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scan&lt;/strong&gt; = several items, by any table attribute&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is very important: the &lt;strong&gt;get&lt;/strong&gt; and &lt;strong&gt;query&lt;/strong&gt; operations are much faster comparing to the &lt;strong&gt;scan&lt;/strong&gt; operation, which has a poor performance and a high cost.&lt;/p&gt;

&lt;p&gt;So it is crucial to model a DynamoDB table in a way that it is possible to query all necessary data, for every access pattern, using get or query operations, and avoiding scan operations.&lt;/p&gt;
&lt;h3&gt;
  
  
  DynamoDB indexes
&lt;/h3&gt;

&lt;p&gt;We may define 2 kinds of indexes on DynamoDB:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GSI = Global Secondary Index = more common, applied to all table items&lt;/li&gt;
&lt;li&gt;LSI = Local Secondary Index = applied to a particular table partition (PK)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It follows the main pros and cons of using DynamoDB indexes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pro: performance: with an index, it is possible to &lt;strong&gt;query&lt;/strong&gt; (instead of &lt;strong&gt;scan&lt;/strong&gt;) on attributes other than the PK/SK&lt;/li&gt;
&lt;li&gt;Con: behind the scenes, each GSI duplicates the table storage, along with its storage costs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is also a limit of 20 GSI per table.&lt;/p&gt;

&lt;p&gt;The following image provides more details on DynamoDB indexes:&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%2Flnkf9hwx5u47ho1y43o4.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%2Flnkf9hwx5u47ho1y43o4.png" alt="Indexes"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  DynamoDB TTL (time to live)
&lt;/h3&gt;

&lt;p&gt;Optionally, a &lt;strong&gt;time to live&lt;/strong&gt; attribute can be defined on DynamoDB tables, and it is very useful on scenarios where items have to be deleted after certain time is reached.&lt;/p&gt;

&lt;p&gt;Another interesting behavior, each table item may have a different time to live value, or no TTL value at all!&lt;/p&gt;
&lt;h2&gt;
  
  
  DynamoDB - Single Table Design
&lt;/h2&gt;

&lt;p&gt;Different from relational databases where we have to &lt;strong&gt;normalize&lt;/strong&gt; the data, it is an AWS recommendation to maintain as few tables as possible when modeling with DynamoDB, as stated on &lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-general-nosql-design.html" rel="noopener noreferrer"&gt;NoSQL Design for DynamoDB&lt;/a&gt; documentation.&lt;/p&gt;

&lt;p&gt;When we normalize data, we make the data access very flexible, but it reduces the scalability, due to the high cost of the joins operations.&lt;/p&gt;

&lt;p&gt;But DynamoDB was built for enormous, high-velocity use cases, such as the Amazon.com shopping cart. Rather than working to make joins scale better, DynamoDB sidesteps the problem by removing the ability to use joins at all!&lt;/p&gt;

&lt;p&gt;Again, DynamoDB was build with web scale in mind. It can grow almost infinitely without degrading performance. In order to achieve this DynamoDB removed joins completely.&lt;/p&gt;

&lt;p&gt;You have to model the data in such a way that you can read the data, ideally, in a single request by &lt;strong&gt;denormalizing&lt;/strong&gt; the data.&lt;/p&gt;

&lt;p&gt;The main reason for using a DynamoDB single table is to retrieve multiple, heterogenous item types using a single request.&lt;/p&gt;

&lt;p&gt;The following links are great to understand more about the single table design concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.alexdebrie.com/posts/dynamodb-single-table/" rel="noopener noreferrer"&gt;The What, Why, and When of Single-Table Design with DynamoDB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serverlessfirst.com/dynamodb-modelling-single-vs-multi-table/" rel="noopener noreferrer"&gt;Comparing multi and single table approaches to designing a DynamoDB data model&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cbannes.medium.com/microservices-with-dynamodb-should-you-use-a-single-table-or-use-one-table-per-microservice-25f54cf610d9" rel="noopener noreferrer"&gt;Microservices with DynamoDB: should you use a single table or use one table per microservice?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Single Table Design - Pros and Cons
&lt;/h3&gt;

&lt;p&gt;Summary of the advantages and disadvantages of applying the single table design:&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%2Fxaynq0coiix67qy42bsx.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%2Fxaynq0coiix67qy42bsx.png" alt="pros and cons"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  DynamoDB - When and how (not) to use
&lt;/h2&gt;

&lt;p&gt;I summarize in the following images when and how to use and not to use DynamoDB:&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%2F60acpgq407ynp4iripts.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%2F60acpgq407ynp4iripts.png" alt="how to use"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;More about &lt;a href="https://www.alexdebrie.com/posts/dynamodb-patterns-serverless/#the-true-microservice" rel="noopener noreferrer"&gt;the true microservice&lt;/a&gt; here. In a nutshell, it favors using a DynamoDB single table per microservice, but not per the whole system.&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%2Ffp09xftsvftoe3hphrd7.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%2Ffp09xftsvftoe3hphrd7.png" alt="how not to use"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Indeed the &lt;strong&gt;Faux SQL&lt;/strong&gt; is a common mistake when starting using a NoSQL database as DynamoDB or MongoDB. More about the &lt;a href="https://www.alexdebrie.com/posts/dynamodb-patterns-serverless/#faux-sql" rel="noopener noreferrer"&gt;Faux SQL&lt;/a&gt; here.&lt;/p&gt;
&lt;h1&gt;
  
  
  DynamoDB - Hands on! &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;
&lt;h2&gt;
  
  
  From Relational to NoSQL
&lt;/h2&gt;

&lt;p&gt;In order to get the hands dirty on the DynamoDB single table design, let's imagine a simple system where we have users and orders.&lt;/p&gt;
&lt;h3&gt;
  
  
  RDBMS:
&lt;/h3&gt;

&lt;p&gt;For this example, in the relational world we could have the following model:&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%2Fp5jry0v006xlk1212dww.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%2Fp5jry0v006xlk1212dww.png" alt="relational model"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  DynamoDB
&lt;/h3&gt;

&lt;p&gt;When we model it with DynamoDB, the first and more important question is: &lt;strong&gt;What are the access patterns for my system?&lt;/strong&gt; &lt;br&gt;
In other words, how the system will query the data in the database?&lt;/p&gt;

&lt;p&gt;For this example we can think about the following access patterns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;List all users&lt;/li&gt;
&lt;li&gt;Get user profile&lt;/li&gt;
&lt;li&gt;Add user&lt;/li&gt;
&lt;li&gt;Edit user&lt;/li&gt;
&lt;li&gt;Delete User&lt;/li&gt;
&lt;li&gt;List all users orders&lt;/li&gt;
&lt;li&gt;List users orders by status&lt;/li&gt;
&lt;li&gt;List users order items&lt;/li&gt;
&lt;li&gt;Add user order&lt;/li&gt;
&lt;li&gt;Edit user order&lt;/li&gt;
&lt;li&gt;Delete user order&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With that in mind, first we can model the user and order documents with the information we would need for all access patterns.&lt;/p&gt;

&lt;p&gt;User example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"adrianosastre"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"fullName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Adriano Sastre Vieira"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"adrianosastre@gmail.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"addresses"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"home"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"My first address"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"home"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"My second address"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Order example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1e499793-1084-4c34-9d4c-bbb9df88d2de"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"adrianosastre"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"fullName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Adriano Sastre Vieira"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"address"&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;"home"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"My first address"&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;"items"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"iPhone"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;999.90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"quantity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those "schemas" result in the following sample data for a DynamoDB single 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%2F1i18u3q8zz7xm7kvm7qz.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%2F1i18u3q8zz7xm7kvm7qz.png" alt="single table"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Important things to note:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;We have in the same table, different items for users and orders information. They even have different attributes. But the important is that they have different patterns in their PK and SK values, and these patterns are used in order to query data for all access patterns.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The "orderStatus" attribute, used only on order items, needs to be used on the "List users orders by status" access pattern. As it is not the PK or SK, we need to create an &lt;strong&gt;index&lt;/strong&gt; in order to query data, not scan. More on that later.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We "denormalize" data, repeating user information inside order information. That's a common practice on DynamoDB and NoSQL modeling in general. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Again, there are more detailed articles explaining how to go from a relational to a NoSQL database, if you wanna go further:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.trek10.com/blog/dynamodb-single-table-relational-modeling/" rel="noopener noreferrer"&gt;From relational DB to single DynamoDB table: a step-by-step exploration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.jeremydaly.com/how-to-switch-from-rdbms-to-dynamodb-in-20-easy-steps/" rel="noopener noreferrer"&gt;How to switch from RDBMS to DynamoDB in 20 easy steps&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  IaC - the Infrastructure as Code
&lt;/h2&gt;

&lt;p&gt;Before configuring the AWS services and coding the business logic, let's do it right!&lt;/p&gt;

&lt;p&gt;Having the infrastructure as code is essential in order to code versioning (ex: git) all the AWS services configuration, instead of making it through the AWS Console (and totally losing control when something goes wrong!).&lt;/p&gt;

&lt;p&gt;IaC is also critical to implement CI/CD pipelines.&lt;/p&gt;

&lt;h3&gt;
  
  
  CloudFormation
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://aws.amazon.com/cloudformation/" rel="noopener noreferrer"&gt;https://aws.amazon.com/cloudformation/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When it comes to the AWS IaC, the most basic level is the CloudFormation. Basically, it consists on yaml or json templates that describes your resources and its dependencies so you can launch and configure them together as a stack. &lt;/p&gt;

&lt;p&gt;In other words, it is an automated process for resources creation. But it is still quite hard and error-prone to program IaC with CloudFormation.&lt;/p&gt;

&lt;h3&gt;
  
  
  CDK - The Cloud Development Kit
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/cdk/api/v2/" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/cdk/api/v2/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=bz4jTx4v-l8" rel="noopener noreferrer"&gt;Released on 2019&lt;/a&gt;, we now have the &lt;strong&gt;AWS CDK&lt;/strong&gt;: the official AWS open source software development framework to define your cloud application resources using familiar programming languages. And now in the end of 2021, we have CDK v2 released.&lt;/p&gt;

&lt;p&gt;With CDK, you can model the infrastructure resources in high-level languages like Java, Typescript, Python or C#.&lt;/p&gt;

&lt;p&gt;Behind the scenes, the CDK will generate the CloudFormation templates and deploy them as AWS CloudFormation Stacks.&lt;/p&gt;

&lt;p&gt;It is much safer, easier and more fun to program AWS IaC code with &lt;strong&gt;CDK&lt;/strong&gt; that with CloudFormation! Also, when compared to other IaC frameworks (e.g. serverless,  terraform, etc), it has the following advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implemented and maintained by AWS &lt;/li&gt;
&lt;li&gt;Easy integration with AWS services&lt;/li&gt;
&lt;li&gt;More secure (e.g. roles automatically generated for services, from read/write permissions)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step by step
&lt;/h2&gt;

&lt;p&gt;Let's get the hands dirty!&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;If not yet, create / install / configure the following:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1 - Create an AWS Account&lt;/strong&gt; if you don't have yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2 - After logged into the AWS Console, add an IAM user&lt;/strong&gt; with "Access type: Programatic access" and for the sake of this example, add the "Administrator Access" policy to this user. Copy its "Access key ID" and "Secret access key", we'll use them soon.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3 - Download and install VS Code&lt;/strong&gt;: &lt;a href="https://code.visualstudio.com/" rel="noopener noreferrer"&gt;https://code.visualstudio.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4 - Install Node and NPM&lt;/strong&gt;: &lt;a href="https://nodejs.org/en/download/" rel="noopener noreferrer"&gt;https://nodejs.org/en/download/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After installing, check their version. At the moment of this writing I have node v16.13.1 and npm 8.3.0&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node -v
npm -v
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5 - Download and install AWS cli&lt;/strong&gt;: &lt;a href="https://aws.amazon.com/cli/" rel="noopener noreferrer"&gt;https://aws.amazon.com/cli/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After installing, check its version and configure it to your AWS account IAM user created on step 2:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws --version
aws configure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6 - Install AWS CDK&lt;/strong&gt;: &lt;/p&gt;

&lt;p&gt;Install CDK via NPM and check its version. At the moment I have 2.3.0 (build beaa5b2)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -g aws-cdk
cdk --version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;7 - Download and install Docker&lt;/strong&gt;: &lt;a href="https://www.docker.com/products/docker-desktop" rel="noopener noreferrer"&gt;https://www.docker.com/products/docker-desktop&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Docker is only used in order to deploy the CDK project into AWS, we do not have containerized AWS services in this example.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8 - Download and install Postman&lt;/strong&gt;: &lt;a href="https://www.postman.com/" rel="noopener noreferrer"&gt;https://www.postman.com/&lt;/a&gt; (used in order to test the APIs)&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&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%2Ft8e4mihxdoy2uhjw1j20.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%2Ft8e4mihxdoy2uhjw1j20.png" alt="architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As per the above architecture, this project consists on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API Gateway, with the /users and /products RESTful resources&lt;/li&gt;
&lt;li&gt;Lambdas: functions for users and orders, they handle the APIs and DynamoDB data&lt;/li&gt;
&lt;li&gt;DynamoDB: one single table to store users and orders data&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Open project on VS Code
&lt;/h3&gt;

&lt;p&gt;This project was implemented with &lt;strong&gt;CDK v2&lt;/strong&gt; with &lt;strong&gt;Typescript&lt;/strong&gt;, and is public available on github:&lt;br&gt;
&lt;a href="https://github.com/adrianosastre/DynamoDB-CDK-Hands-On" rel="noopener noreferrer"&gt;github.com/adrianosastre/DynamoDB-CDK-Hands-On&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please clone and open it on VS Code, and look at these important chunks of code:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1 - Resources application stack&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;lib/resources-application-stack.ts&lt;/strong&gt; file is &lt;strong&gt;IaC&lt;/strong&gt; code, it creates the DynamoDB table and the users and orders Lambdas. &lt;/p&gt;

&lt;p&gt;Important things to note:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The "singleTable" constant contains all DynamoDB table configuration: the PK, the SK, the GSI, the table capacity and scaling configuration on a few lines of code with CDK. In other words, modeling the data is complex, but implementing its infrastructure with CDK is simple.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The "grantReadWrite" method that manages the lambda permissions on the DynamoDB table. Again, CDK takes care of services permissions in a very easy and efficient way.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The lambdas were implemented as class readonly public attributes, so they can be accessed later on the API stack.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2 - API stack&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;lib/api-gateway-stack.ts&lt;/strong&gt; file, also an &lt;strong&gt;IaC&lt;/strong&gt; code, creates the API Gateway with our users and orders resources. &lt;/p&gt;

&lt;p&gt;Note that it uses the lambdas exposed on the &lt;strong&gt;lib/resources-application-stack.ts&lt;/strong&gt; file in order to integrate its resources with the lambdas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3 - The CDK main file&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The file under the bin directory, in this case the &lt;strong&gt;bin/dynamoDB-CDK-Hands-On-Project.ts&lt;/strong&gt; file, is the main file in the CDK structure. &lt;/p&gt;

&lt;p&gt;It instantiates the stacks and care about its dependencies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4 - Lambdas code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;users.js&lt;/strong&gt; and &lt;strong&gt;orders.js&lt;/strong&gt; files under &lt;strong&gt;lambda&lt;/strong&gt; directory are not IaC code. &lt;/p&gt;

&lt;p&gt;Instead, they are the "core" of the system, containing the business logic code behind the lambdas, and are executed every time they are triggered.&lt;/p&gt;
&lt;h3&gt;
  
  
  Deploying on AWS
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Note: AWS cli must be correctly configured as explained in the Prerequisites session.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Only once, it is necessary to execute the following command so the CDK will deploy into your AWS account the required resources for it to deploy projects:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;After that, you can deploy the project to your AWS account via the following command:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Every time you change the IaC or lambda code, you can use this command to redeploy, and it does not impact the services usage!&lt;/p&gt;

&lt;p&gt;After the project is deployed, you can check in your AWS account the following resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://console.aws.amazon.com/cloudformation" rel="noopener noreferrer"&gt;&lt;strong&gt;CloudFormation&lt;/strong&gt;&lt;/a&gt;: the stacks with the resources programmed via CDK were deployed here:&lt;/li&gt;
&lt;/ul&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%2Fp45fqn28ip2iov24o69q.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%2Fp45fqn28ip2iov24o69q.png" alt="cloudformation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://console.aws.amazon.com/apigateway/main/apis" rel="noopener noreferrer"&gt;&lt;strong&gt;API Gateway&lt;/strong&gt;&lt;/a&gt;: the DynamoDB-CDK-Hands-On-API API is deployed and public available:&lt;/li&gt;
&lt;/ul&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%2F4k4rvgkjclg5hf1mzvzy.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%2F4k4rvgkjclg5hf1mzvzy.png" alt="api gateway"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the API expanded showing its resources:&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%2Fhevimw31qqjj6yz8zwtl.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%2Fhevimw31qqjj6yz8zwtl.png" alt="api gateway expanded"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In addition, the Stages &amp;gt; prod &amp;gt; &lt;strong&gt;Invoke URL&lt;/strong&gt; shows the base URL for this API, so you can use it, for example, with Postman:&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%2Fqxpk4c75kb3vt2ia7urd.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%2Fqxpk4c75kb3vt2ia7urd.png" alt="base url"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://console.aws.amazon.com/lambda" rel="noopener noreferrer"&gt;&lt;strong&gt;Lambda&lt;/strong&gt;&lt;/a&gt;: the functions to handle users and orders are deployed:&lt;/li&gt;
&lt;/ul&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%2Fb8r7tluc2wgxe0yvfnpc.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%2Fb8r7tluc2wgxe0yvfnpc.png" alt="lambdas"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://console.aws.amazon.com/dynamodb" rel="noopener noreferrer"&gt;&lt;strong&gt;DynamoDB&lt;/strong&gt;&lt;/a&gt;: The DynamoDB-CDK-Hands-On-Single-Table table was also created and deployed:&lt;/li&gt;
&lt;/ul&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%2Fjad3asec8fxtgysipxez.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%2Fjad3asec8fxtgysipxez.png" alt="dynamodb"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, at this moment you can see that the table have no items, and you can also double-check its capacity configuration:&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%2Fg3jiz91zeywt0ph5d7uf.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%2Fg3jiz91zeywt0ph5d7uf.png" alt="dynamodb capacity"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing with Postman
&lt;/h3&gt;

&lt;p&gt;After deployed, it is possible to test all the project URLs with Postman. Take the following images as references and use Postman with your API base URL.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adding users:&lt;/li&gt;
&lt;/ul&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%2Fqirc5ppk4001jufwk9ri.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%2Fqirc5ppk4001jufwk9ri.png" alt="add user"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the lambda/users.js code, the &lt;strong&gt;put&lt;/strong&gt; method from the DDB client was used:&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%2F0d7mtdvkfyjysr9c0nqi.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%2F0d7mtdvkfyjysr9c0nqi.png" alt="add user lambda"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Listing all users:&lt;/li&gt;
&lt;/ul&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%2Fhohlmzvjmmaspiusl8iu.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%2Fhohlmzvjmmaspiusl8iu.png" alt="list all users"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the lambda/users.js code, the &lt;strong&gt;query&lt;/strong&gt; method from the DDB client was used, and only querying the "USER#" value in the PK returned the results we want:&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%2Fpxo9odc8j89457lfawt6.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%2Fpxo9odc8j89457lfawt6.png" alt="list users lambda"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Getting a user profile data:&lt;/li&gt;
&lt;/ul&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%2F9ofhj6e9bh97m6kk8xr2.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%2F9ofhj6e9bh97m6kk8xr2.png" alt="get user profile"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the lambda/users.js code, the &lt;strong&gt;get&lt;/strong&gt; method from the DDB client was used, in this case we need to provide values for the PK and SK to retrieve a specific item:&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%2Fws5c7t1n93znp62ai2z1.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%2Fws5c7t1n93znp62ai2z1.png" alt="get user profile lambda"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Editing a user:&lt;/li&gt;
&lt;/ul&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%2Ffs7h5lrp1diav16t2r5t.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%2Ffs7h5lrp1diav16t2r5t.png" alt="edit user"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the lambda/users.js code, the &lt;strong&gt;update&lt;/strong&gt; method from the DDB client was used, and we provided values for the PK and SK to update a specific item:&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%2Fgin76tgtrujoq41zreyt.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%2Fgin76tgtrujoq41zreyt.png" alt="edit user lambda"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deleting a user:&lt;/li&gt;
&lt;/ul&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%2Favpah36hcn6vu0atghyx.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%2Favpah36hcn6vu0atghyx.png" alt="delete user"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the lambda/users.js code, the &lt;strong&gt;delete&lt;/strong&gt; method from the DDB client was used, and again we provided values for the PK and SK to delete a specific item:&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%2F1glmzzgctwsqtehyrz75.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%2F1glmzzgctwsqtehyrz75.png" alt="delete user lambda"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adding an order for a user:&lt;/li&gt;
&lt;/ul&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%2F6hrfe3bury6z5wur334w.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%2F6hrfe3bury6z5wur334w.png" alt="add order"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Listing all orders for each user:&lt;/li&gt;
&lt;/ul&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%2Fvifc21u1n9uh5omczmqk.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%2Fvifc21u1n9uh5omczmqk.png" alt="list user orders 1"&gt;&lt;/a&gt;&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%2F3puz4fuq1053b513hj3j.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%2F3puz4fuq1053b513hj3j.png" alt="list user orders 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the lambda/orders.js code, the &lt;strong&gt;query&lt;/strong&gt; method from the DDB client was used, and querying the "ORDER#${username}" value in the PK returned the results we want: &lt;em&gt;(note that we have one order partition per username)&lt;/em&gt;&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%2F7olvdjmmi132kh38nyrf.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%2F7olvdjmmi132kh38nyrf.png" alt="list user orders lambda"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Listing users orders by status:&lt;/li&gt;
&lt;/ul&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%2Fkhz8urbt8pcega1k6y8i.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%2Fkhz8urbt8pcega1k6y8i.png" alt="orders by status"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the lambda/orders.js code, the &lt;strong&gt;query&lt;/strong&gt; method from the DDB client was used, and here we used the &lt;strong&gt;index&lt;/strong&gt; value so we can search for attribute values &lt;strong&gt;without using scan&lt;/strong&gt; in order to get the results we want:&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%2Fxdqsdnqy1cep4xx6tpwk.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%2Fxdqsdnqy1cep4xx6tpwk.png" alt="orders by status lambda"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Listing a user specific order items:&lt;/li&gt;
&lt;/ul&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%2Fap388sg5lsrgs6qvh0rx.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%2Fap388sg5lsrgs6qvh0rx.png" alt="order items"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Editing user order:&lt;/li&gt;
&lt;/ul&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%2Fxiiua9ymqm48m9j7mov0.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%2Fxiiua9ymqm48m9j7mov0.png" alt="edit user order"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deleting user order:&lt;/li&gt;
&lt;/ul&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%2F1a5c6odsdcu3rnznb3zr.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%2F1a5c6odsdcu3rnznb3zr.png" alt="delete order"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  AWS troubleshooting
&lt;/h3&gt;

&lt;p&gt;Things does not always go right from the first time. &lt;/p&gt;

&lt;p&gt;In order to troubleshoot AWS services, e.g. the lambdas code, their logs results that can be double-checked on &lt;a href="https://console.aws.amazon.com/cloudwatch/home#logsV2:log-groups" rel="noopener noreferrer"&gt;AWS CloudWatch Log Groups&lt;/a&gt;. Just click on the respective log group:&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%2Fdjqw75125emqrgr6hm4g.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%2Fdjqw75125emqrgr6hm4g.png" alt="cloudwatch log group"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And after that, in the log stream messages:&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%2Fks7i8k48iborilvj3ga3.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%2Fks7i8k48iborilvj3ga3.png" alt="log streams"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Remember, logs are our best friends! As stated on this great old &lt;a href="https://testing.googleblog.com/2013/06/optimal-logging.html" rel="noopener noreferrer"&gt;&lt;strong&gt;Optimal Logging&lt;/strong&gt;&lt;/a&gt; article, &lt;em&gt;"With optimal logging, you can even eliminate the necessity for debuggers!"&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Tracking performance
&lt;/h3&gt;

&lt;p&gt;Last but not least, in order to track performance, this project lambdas also have &lt;strong&gt;X-Ray&lt;/strong&gt; enabled so you can verify X-Ray traces in &lt;a href="https://console.aws.amazon.com/cloudwatch/home#servicelens:traces" rel="noopener noreferrer"&gt;&lt;strong&gt;ServiceLens&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It is so cool and useful to graphically see the services flow and how much time was spent in each service or function!&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%2Fjdbamd0e8psfxf1gavlb.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%2Fjdbamd0e8psfxf1gavlb.png" alt="x-ray 1"&gt;&lt;/a&gt;&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%2Fvi5b16q9336qzt2c9ijs.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%2Fvi5b16q9336qzt2c9ijs.png" alt="x-ray 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can perform load tests with Postman, for example configuring it to send several user or order edit operations, and monitor the performance on AWS Console as per the above images.&lt;/p&gt;

&lt;h1&gt;
  
  
  That's all folks!
&lt;/h1&gt;

&lt;p&gt;I hope this article was helpful, and I'm available for any comments or questions here or via &lt;a href="mailto:adrianosastre@gmail.com"&gt;adrianosastre@gmail.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks and have a nice 2022 :)&lt;/p&gt;

</description>
      <category>aws</category>
      <category>node</category>
      <category>serverless</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
