AWS SDK v3: Putting an Item

AWS SDK v3 is the latest version of the SDK from AWS, offering modularized packages, better performance, and improved developer experience. In this blog post, we'll focus on how to use the AWS SDK for JavaScript v3 to perform a basic operation: putting an item into a DynamoDB table.

14 days ago   •   4 min read

By Maik Wiesmüller
Table of contents

Motivation

After a recent session on how to handle the DynamoDB put item usecase I decided to wrap up the main topics of the discussion. I hope this helps somebody getting started.

Prerequisites

Before diving in, ensure you have the following:

  1. AWS Account: the obvious one...
  2. Node.js: Install Node.js (I prefer typescript).
  3. AWS CLI (optional): if you want to follow through, otherwise just create the table manually.

Install the necessary packages:

yarn add @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb

Setting up AWS credentials

The AWS SDK uses your credentials to authenticate and perform actions. You can configure these credentials using the AWS CLI:

aws configure

Alternatively, you can set the following environment variables:

export AWS_ACCESS_KEY_ID=your_access_key_id
export AWS_SECRET_ACCESS_KEY=your_secret_access_key
export AWS_REGION=your_region

Creating a DynamoDB table

To follow along, create a DynamoDB table in the AWS Management Console or using the AWS CLI. Here's an example of a simple table:

aws dynamodb create-table \
  --table-name ExampleTable \
  --attribute-definitions AttributeName=PK,AttributeType=S \
  --key-schema AttributeName=PK,KeyType=HASH \
  --billing-mode PAY_PER_REQUEST

This creates a table named ExampleTable with a partition key (PK) of type String.

Writing code to put an item using DynamoDBClient

Now, let's write a script to insert an item into the table using DynamoDBClient:

import {DynamoDBClient, PutItemCommand} from "@aws-sdk/client-dynamodb";

// Initialize DynamoDB client
const client = new DynamoDBClient({region: "eu-central-1"});

// Define the item to insert
const params = {
    TableName: "ExampleTable",
    Item: {
        PK: {S: "example-key"},
        Name: {S: "Example Name"},
        Age: {N: "30"},
    },
};

async function putItem() {
    const command = new PutItemCommand(params);
    return await client.send(command);
}

putItem()
    .then(res => console.log(res))
    .catch(err => console.log(err));

Using DynamoDBDocumentClient

Before we dive into using the DynamoDBDocumentClient, let's take a moment to understand the JavaScript object syntax in the code. The DynamoDBClient requires explicit typing for attributes (e.g., S for string, N for number, full list here), which can feel verbose and cumbersome.

For example:

Item: {
  PK: { S: "example-key" },
  Name: { S: "Example Name" },
  Age: { N: "30" },
}

Each attribute is represented as a key-value pair where the key is the attribute name, and the value is an object that defines the type and the actual value. While precise, this can make the code harder to read and maintain, especially for large or complex items (especially when nested).

The DynamoDBDocumentClient simplifies this by allowing developers to work with plain JavaScript objects. Instead of specifying types explicitly, it handles the type conversion for you. This improves readability by a lot. and also reduces the likelihood of errors.

Here's how you can use the DynamoDBDocumentClient for a simpler experience:

The DynamoDBDocumentClient simplifies working with DynamoDB by abstracting the data types (S, N, etc.) and allowing you to work with native JavaScript objects. Here's how to use it:

import {DynamoDBDocumentClient, PutCommand} from "@aws-sdk/lib-dynamodb";
import {DynamoDBClient} from "@aws-sdk/client-dynamodb";

// Initialize DynamoDB client and Document client
const client = new DynamoDBClient({region: "eu-central-1"});
const docClient = DynamoDBDocumentClient.from(client);

// Define the item to insert
const params = {
    TableName: "ExampleTable",
    Item: {
        PK: "example-key-doc",
        Name: "Example Name",
        Age: 30,
    },
};

async function putItemWithDocClient() {
    const command = new PutCommand(params);
    return await docClient.send(command);
}

putItemWithDocClient()
    .then(res => console.log(res))
    .catch(err => console.log(err));

Explanation of the code

  1. DynamoDBClient: Used to create the low-level client to interact with DynamoDB.
  2. DynamoDBDocumentClient: A higher-level abstraction that simplifies operations by handling type conversion for you.
  3. PutCommand: Similar to PutItemCommand, but works seamlessly with native JavaScript objects.
  4. docClient.send(): Sends the command to DynamoDB.

Testing the script

Run the script:

npx ts-node put_doc_client.ts    

Check your DynamoDB table in the AWS Management Console to verify that the item was inserted.

It should look like this:

{
  "PK": {
    "S": "example-key-doc"
  },
  "Age": {
    "N": "30"
  },
  "Name": {
    "S": "Example Name"
  }
}

Writing over an existing item

When putting an item into a DynamoDB table, if an item with the same primary key already exists, the new item will overwrite the existing one. Let's explore some specific cases and their outcomes:

Setting an attribute to null: If you explicitly set an attribute to null, DynamoDB will store it as a NULL type in the table:

const params = {
  TableName: "ExampleTable",
  Item: {
    PK: "example-key",
    Name: "Updated Name",
    Age: null, // Stored as NULL type
  },
};

This can be useful if you want to explicitly represent the absence of a value while preserving the attribute in the item.

It should look like this:

{
  "PK": {
    "S": "example-key-doc"
  },
  "Age": {
    "NULL": true
  },
  "Name": {
    "S": "Example Name"
  }
}

Skipping an attribute: If you skip an attribute in the new item, DynamoDB will remove it from the existing item. Or better said: simply put over the existing one. For example:

const params = {
  TableName: "ExampleTable",
  Item: {
    PK: "example-key",
    Name: "Updated Name",
    // Age is not included
  },
};

The Age attribute will not be in the item with PK of example-key.

Setting an attribute to undefined: will behave the same as skipping.

const params = {
  TableName: "ExampleTable",
  Item: {
    PK: "example-key",
    Name: "Updated Name",
    Age: undefined, // Invalid
  },
};

Updating only specific attributes: If you only want to update or delete some attributes, you need to use UpdateItem with the proper UpdateExpression (documentation)

If you really really want to do it with PutItem: you read the existing item, make your changes and PutItem it back.

BUT I highly recommend looking into optimistic locking to avoid race conditions and other concurrency related challenges.

Conclusion

AWS SDK v3 makes interacting with DynamoDB straightforward. It's pretty easy to perform the basic "put item" operation using both DynamoDBClient and DynamoDBDocumentClient!

Don't forget to clean up the created resources.

Spread the word

Keep reading