🎉 I'm releasing 12 products in 12 months! If you love product, checkout my new blog workingoutloud.dev

Back to home

DynamoDB With LocalStack And The AWS CDK (Part 2)

Today's post will demonstrate usage of DynamoDB Toolbox for our single-table design.

This post will continue on from the work done yesterday in part one.

Be sure to check that out to understand where we are up to.

The final code for today's post will be in my GitHub repository.

Prerequisites

  1. Read part one.
  2. Have the code from part one ready.

Getting started

Let's clone our code from part one in this demonstration to keep things segregated.

$ git clone https://github.com/okeeffed/dynamodb-with-localstack-and-the-aws-cdk dynamodb-with-localstack-and-the-aws-cdk-part-two $ cd dynamodb-with-localstack-and-the-aws-cdk-part-two $ rm package-lock.json $ rm -rf .git $ git init $ npm i # Add the packages that we need for today $ npm i dynamodb-toolbox aws-sdk faker $ npm i --save-dev @types/faker # Create some files for today's work $ mkdir src scripts $ touch src/customer.ts scripts/putCustomers.ts scripts/getCustomers.ts

At this stage, we will have all the tools we need to get started.

Using DynamoDB Toolbox to put and get customers

Inside of src/customer.ts, add the following:

import { DynamoDB } from "aws-sdk"; import { Entity, Table } from "dynamodb-toolbox"; import * as faker from "faker"; // Require AWS SDK and instantiate DocumentClient const DocumentClient = new DynamoDB.DocumentClient({ endpoint: `http://localhost:4566`, }); // Instantiate a table const MyTable = new Table({ // Specify table name (used by DynamoDB) name: "my-table", // Define partition and sort keys partitionKey: "pk", sortKey: "sk", // Add the DocumentClient DocumentClient, }); type Customer = { pk: number; sk: string; name: string; company: string; age: number; status: string; data_added: string; }; const Customer = new Entity<Customer>({ // Specify entity name name: "Customer", // Define attributes attributes: { id: { partitionKey: true }, // flag as partitionKey sk: { hidden: true, sortKey: true }, // flag as sortKey and mark hidden name: { map: "data" }, // map 'name' to table attribute 'data' co: { alias: "company" }, // alias table attribute 'co' to 'company' age: { type: "number" }, // set the attribute type status: ["sk", 0], // composite key mapping date_added: ["sk", 1], // composite key mapping }, // Assign it to our table table: MyTable, }); export const addCustomer = async (): Promise<void> => { const item = { id: faker.datatype.uuid(), name: faker.name.findName(), company: faker.company.companyName(), age: Math.floor(Math.random() * 100), status: "active", date_added: "2020-04-24", }; // Use the 'put' method of Customer await Customer.put(item); }; export const scanTable = async (): Promise<any> => { const res = await MyTable.scan({ limit: 10, }); return res; };

In this file, we are setting up the DynamoDB.DocumentClient to point towards LocalStack, then creating a table with the toolbox based on our tableName from the stack we built yesterday, as well as our partitionKey and soretKey

Within the new Entity invocation, we are defining what our table will hold.

If it important to know that id will map to the table's partition key pk and status and date_added will combine to create the sk. For example, a status of active and a date_added of 2020-04-24 will create the sk active#2020-04-24.

While this post won't go into the "do and don't do" of single-table design, we will use that to illustrate how to interact with the LocalStack table.

We have two helper functions: addCustomer and scanTable. We will use these to demonstrate adding some customers (with fake date through faker) and scanning the table.

Writing the scripts

Inside of scripts/putCustomers.ts, add the following:

import { addCustomer } from "../src/customer"; async function main() { for (let i = 0; i < 100; i++) { // yes, we are doing this the slow way for the demo await addCustomer(); } console.log("Done"); } main();

Inside of scripts/getCustomers.ts, add the following:

import { scanTable } from "../src/customer"; async function main() { const res = await scanTable(); console.log(res); } main();

In order to be able to run these scripts, we will need to add a new script to package.json:

{ "scripts": { "ts": "ts-node" } }

This will allow us to run our TypeScript files.

Running our scripts with LocalStack

At this stage, ensure that LocalStack is running and that the table has been deploy through the AWS CDK:

# In one terminal tab $ docker compose up # In another tab when LocalStack is ready $ npm run local synth && npm run local deploy

Once everything is up and ready, we can add our customers:

$ npm run ts scripts/putCustomers.ts Done

Note: If you have issues, check that you have your AWS credentials and region in your environment variables.

To confirm that we can interact with our table as expected, we can now run our scan and confirm that the table does in fact have our generated users!

$ npm run ts scripts/getCustomers.ts > aws-cdk-with-typescript-foundations@0.1.0 ts > ts-node "scripts/getCustomers.ts" { Items: [ { created: '2021-08-09T22:18:21.153Z', date_added: '2020-04-24', name: 'Bert Upton', modified: '2021-08-09T22:18:21.153Z', id: '572657d5-41fb-45d8-8747-75fde1c5c26f', company: 'Flatley Inc', age: 17, entity: 'Customer', status: 'active' }, { created: '2021-08-09T22:18:23.059Z', date_added: '2020-04-24', name: 'Lloyd Beer', modified: '2021-08-09T22:18:23.059Z', id: '8724af8c-c448-4448-83b1-9c3c3c38b501', company: 'McGlynn Inc', age: 10, entity: 'Customer', status: 'active' }, { created: '2021-08-09T22:18:22.641Z', date_added: '2020-04-24', name: 'Terrell Donnelly', modified: '2021-08-09T22:18:22.641Z', id: '384efa80-debd-406f-b2fc-88413c38b4f6', company: 'Bode, Cummings and Heathcote', age: 47, entity: 'Customer', status: 'active' }, { created: '2021-08-09T22:18:24.709Z', date_added: '2020-04-24', name: 'Doreen Sanford', modified: '2021-08-09T22:18:24.709Z', id: '58d0901f-4f1b-4664-bb05-5e3248235eeb', company: 'Jenkins, Gutmann and Trantow', age: 97, entity: 'Customer', status: 'active' }, { created: '2021-08-09T22:18:23.877Z', date_added: '2020-04-24', name: 'Alice Connelly', modified: '2021-08-09T22:18:23.877Z', id: 'b04f40d8-b775-4f2e-b0bc-688224a6a522', company: 'Rowe - Jenkins', age: 71, entity: 'Customer', status: 'active' }, { created: '2021-08-09T22:18:24.630Z', date_added: '2020-04-24', name: 'Lloyd Wunsch', modified: '2021-08-09T22:18:24.630Z', id: '040d088c-57e1-4d3d-a8ac-34370b0d5f48', company: 'Cummings Group', age: 4, entity: 'Customer', status: 'active' }, { created: '2021-08-09T22:18:23.646Z', date_added: '2020-04-24', name: 'Jermaine Nikolaus', modified: '2021-08-09T22:18:23.646Z', id: '8dd4ae85-a123-4bd2-9af0-e0099eec7273', company: 'Barrows, Powlowski and Feeney', age: 89, entity: 'Customer', status: 'active' }, { created: '2021-08-09T22:18:24.753Z', date_added: '2020-04-24', name: 'Tasha DuBuque', modified: '2021-08-09T22:18:24.753Z', id: '2640bf11-ad67-4a35-b207-403c362041a2', company: 'Metz Group', age: 35, entity: 'Customer', status: 'active' }, { created: '2021-08-09T22:18:21.733Z', date_added: '2020-04-24', name: 'Mr. Terry Gorczany', modified: '2021-08-09T22:18:21.733Z', id: '241d1d2c-b93c-4b8a-a1f0-702686c3cef9', company: 'Schumm - Daniel', age: 36, entity: 'Customer', status: 'active' }, { created: '2021-08-09T22:18:24.550Z', date_added: '2020-04-24', name: 'Reginald Osinski', modified: '2021-08-09T22:18:24.550Z', id: 'd5892a47-9850-4ba1-aa7f-298915eaad37', company: 'Lueilwitz and Sons', age: 26, entity: 'Customer', status: 'active' } ], Count: 10, ScannedCount: 10, LastEvaluatedKey: { sk: 'active#2020-04-24', pk: 'd5892a47-9850-4ba1-aa7f-298915eaad37' }, next: [Function: next] }

When we scan the table, you will notice that the users are all mapped back to their expected values as defined in our Table.

Teardown

As per usual, once you are done we can tear down the stack:

$ npm run local destroy > aws-cdk-with-typescript-foundations@0.1.0 local > cdklocal "destroy" Are you sure you want to delete: AwsCdkWithTypescriptFoundationsStack (y/n)? y AwsCdkWithTypescriptFoundationsStack: destroying... ✅ AwsCdkWithTypescriptFoundationsStack: destroyed

Summary

Today's post demonstrated how to interact with the DynamoDB table that we created on LocalStack through the DynamoDB toolbox.

Albeit simple, we generated 100 users in our table and scanned for the first ten.

Resources and further reading

Photo credit: waldemarbrandt67w

Personal image

Dennis O'Keeffe

@dennisokeeffe92
  • Melbourne, Australia

Hi, I am a professional Software Engineer. Formerly of Culture Amp, UsabilityHub, Present Company and NightGuru.
I am currently working on Visibuild.

1,200+ PEOPLE ALREADY JOINED ❤️️

Get fresh posts + news direct to your inbox.

No spam. We only send you relevant content.

DynamoDB With LocalStack And The AWS CDK (Part 2)

Introduction

Share this post