# DynamoDB With LocalStack And The AWS CDK (Part 2)

> The second part of this demo will show how to interact with our DynamoDB table using DynamoDB Toolbox.

- Canonical: https://dennisokeeffe.com/blog/2021-08-10-dynamodb-with-localstack-and-the-aws-cdk-part-two
- Published: 2021-08-10
- Updated: 2021-08-10
- Tags: aws, aws cdk, typescript

Today's post will demonstrate usage of [DynamoDB Toolbox](https://github.com/jeremydaly/dynamodb-toolbox) for our single-table design.

This post will continue on from the work done yesterday in [part one](https://blog.dennisokeeffe.com/blog/2021-08-09-dynamodb-with-localstack-and-the-aws-cdk).

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](https://github.com/okeeffed/dynamodb-with-localstack-and-the-aws-cdk-part-two).

## Prerequisites

1. [Read part one](https://blog.dennisokeeffe.com/blog/2021-08-09-dynamodb-with-localstack-and-the-aws-cdk).
2. [Have the code from part one ready](https://github.com/okeeffed/dynamodb-with-localstack-and-the-aws-cdk).

## Getting started

Let's clone our code from [part one](https://github.com/okeeffed/dynamodb-with-localstack-and-the-aws-cdk) in this demonstration to keep things segregated.

```s
$ 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:

```ts
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:

```ts
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:

```ts
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`:

```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:

```s
# 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:

```s
$ 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!

```s
$ 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:

```s
$ 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

1. [AWS CDK for TypeScript](https://docs.aws.amazon.com/cdk/latest/guide/work-with-cdk-typescript.html)
2. [DynamoDB Toolbox](https://github.com/jeremydaly/dynamodb-toolbox)
3. [DynamoDB with LocalStack and the AWS CDK Part One](https://blog.dennisokeeffe.com/blog/2021-08-09-dynamodb-with-localstack-and-the-aws-cdk)
4. [Final code](https://github.com/okeeffed/dynamodb-with-localstack-and-the-aws-cdk-part-two)

_Photo credit: [`waldemarbrandt67w`](https://unsplash.com/@waldemarbrandt67w)_
