Getting started with AWS-SDK v3

When you try to install the latest aws-sdk, through npm i, it will still give you the latest v2. This is because version 3 does not work as a whole aws-sdk anymore, but instead has modularised packages.

Meaning, instead of installing the whole SDK, you install the specific client that you need. For example, the DynamoDBClient or the CognitoIdentityProviderClient. So instead of running npm i aws-sdk, if you want to use the DynamoDB SDK, you run npm i @aws-sdk/client-dynamodb.

What may take some getting used to, but is actually a beautiful pattern once you’re familiar with it, is that there is a similarity to all the calls you make. No matter to what module or part of the SDK. You will always send a command, with some input, getting output. For illustration, let’s stay close to DynamoDB and I will use this as an example throughout this post.

As said, for every call to the SDK you need 4 things:
1. A client (see below)
2. A command (see below)
3. Input (the Input type)
4. Output (the Output type)

The Client
The v3 SDK provides ‘AWS Services package clients’. These clients enable you to perform an operation for that specific AWS Service. Since this is a separate module, on run time you will only need to load this specific client. Especially on the serverless stack, this can save some cold start time for your Lambdas. In the API Reference you can easily find which clients there are, since they all start with ‘@aws-sdk/client-‘.

The Command
On the client you can perform certain commands. To find these I personally use the API Reference documentation. As example, take a look at the client-dynamodb. In case we want to get an item for DynamoDB, we look at the GetItemCommand. Here we also see the Input type, Output type and possible Configurations to add to the command.

You can still call the SDK v3 in the v2 style, with callbacks, but it is not recommended. You can now also use Promises or the Async/await pattern. Since I am personally a bigger fan of the latter I will use that in the examples as well.

So before stepping into code examples, let’s first explain the pattern you will see on all the calls. You need to go through the following steps:
1. Import the 4 things you need mentioned above.
2. Initialize the Client.
3. Define the Input parameters.
4. Initialize the Command with the Input params.
5. Call the ‘send‘ method on the Client.
6. Get the Output from the send method.

So let’s look at an actual code example of what this would look like.

import { DynamoDBClient, GetItemCommand, GetItemInput, GetItemOutput } from '@aws-sdk/client-dynamodb';
import { marshall, unmarshall } from '@aws-sdk/util-dynamodb';

export class ItemNotFoundError extends Error {}

export async function getItemFromDynamo(key: string) {
  try {
    const documentClient = new DynamoDBClient({ region: process.env.REGION });

    const getItemInput: GetItemInput = {
      TableName: process.env.tableName,
      Key: marshall({ key }),
    };
    const command = new GetItemCommand(getItemInput);

    const getItemResponse: GetItemOutput = await documentClient.send(command);

    if (!getItemResponse.Item) {
      throw new ItemNotFoundError(`Item: ${key} not found`);
    }
    return unmarshall(getItemResponse.Item);
  } catch (err) {
    throw new Error(`Error getting Item: ${key} | Error: ${JSON.stringify(err)}`);
  }
}

Alright, so on line 1 we see the import statements as mentioned. Now in this utility class, we get the key for the item we are looking for as an input parameter.
On line 8 we initialise the client with the region we have set on the environment variable (the region your DynamoDB is in).
On line 10 we declare the input parameter that we need to reach the correct table and set the key.
On line 12 & 21 we use the utilities to marshall & unmarshall (see below).
On line 14 you can see we initialised the command based on the input param.
Finally, on line 16 we actually send the command on the client and get the results back.

As mentioned, a call to a different client, for example Route53, or pick any client you like, will have the same structure of commands, input & output. The modularised packages will make your code run quicker and once used to the structure, I personally find it very readable and understandable.
The documentation and finding all the details might take you some more time of getting used to.

Utilities
The AWS SDK page also mentions a couple of utility libraries, make sure you scroll all the way down on the index page to check them out. In this code example, I used the Dynamo Utilities. You install these through npm i @aws-sdk/util-dynamodb. In there the marshall and unmarshall functions are very useful. This helps you to convert JSON from and to a DynamoDB record.

Resources:
AWS SDK for JavaScript
AWS API Reference
DynamoDB Utilities