AWS DynamoDB and Lambda Functions

In this post, we will make a Lambda Function that interfaces with DynamoDB in AWS. To follow along, you will need an AWS account and have the aws-cli installed. We’ll also use node and npm as our environment.

Setting up DynamoDb

In the DynamoDB AWS Console, create a New Table. I will call my table cityZoo. Give it a partition key. I’ll use id as type string.

screenshot of creating a creating a DynamoDB table with AWS console A screenshot of creating a creating a DynamoDB table with AWS console

Creating a Function and Setting up a Role for you Lambda Functions

In the AWS console, click on Create Function. We will write one from scratch, so you can click the Author from scratch button.

I’ll call my function addToCityZoo.

We will need extra permissions to access DynamoDB, so we will create a new role with the right permissions. To set the role, scroll down on the same page and click on Change default execution role to see the options. We will click on Create a new role from AWS policy templates. Now choose click on Policy templates and search for DynamoDb Microservice. (The exact name of the policy template can change over time!) This will give us the permissions to perform CRUD operations in a DynamoDB database. Now you can click Create Function Once you have made one Role like this, you can re-use the same Role for other Lambda Functions you create.

screenshot of creating a Role in the AWS console A screenshot of setting permissions for your Role

Writing a Lambda Function

Now it is time to write a function in JavaScript to perform actions on the database. There I will write them locally and upload them. AWS has a simple web based IDE, but you can’t install npm modules there. So, we will need to upload our function and the node_modules directory as a zip file if we have dependencies. But after you have uploaded the node_modules once, you *CAN* use the online IDE to edit if you wish.

Here is a simple function to get started.

// index.js
const handler = async(event) => {
  // TODO implement
  const response = {
    statusCode: 200,
    body: JSON.stringify('Hello, from the City Zoo!'),
  };
  return response;
};

module.exports = { handler };

Uploading our function

To upload using aws-cli, you need to zip the files first, then update the function. For more details from the docs, see here.

Here are the three commands I use. The file local file should be named index.js (or index.mjs if you are using es6 import syntax). And I am using addToCityZoo as the Lambda Function’s name in the cloud.

# remove the old zip file if you have created one already
$ rm lambda.zip 

# zip the current dir (except for the lambda.zip file)
$ zip -r lambda.zip . -x lambda.zip

# use aws-cli to upload to addToCityZoo
$ aws lambda update-function-code --function-name addToCityZoo --zip-file fileb://lambda.zip

(You may have to specify the region or set up local permissions before you can upload using aws-cli.)

So, each time you update, you will have to run these three commands. Ideally, this would be put into a script.

You could also install aws-sam and follow the tutorial on how to create and upload Lambda Functions. There are even AWS extensions for VSCode and many other IDEs.

Invoking the function

We can test the function from the AWS Console, but we can also test it with the aws-cli. For more details read the documentation here.

$ aws lambda invoke --function-name addTocityZoo --invocation-type RequestResponse lambda-results.txt

$ cat lambda-results.txt
{"statusCode":200,"body":"\"Hello, from the City Zoo!\""}

Creating your model

We will use Dynamoose to access DynamoDB.

npm install dynamoose 

First, let’s set up a model for our zoo. One thing to remember is to tell Dynamoose not to create your tables when it called in the Lambda Function. Our permissions don’t allow for creating a table, and you will get an error if you attempt to create a new table from within the Lambda Function. (Remember, we’ve already created the table using the AWS Console.) For this, you can use a config object with create set to false.

// animal.js
const dynamoose = require("dynamoose");

// Define our schema
const animalSchema = new dynamoose.Schema({
    id: String,
    name: String,
    species: String
});

// don't attempt to create a table in DynamoDb
const configObj = {
  create: false,
  update: false,
  waitForActive: false
};

// Initialize our model
const AnimalModel = dynamoose.model("cityZoo",
  animalSchema,
  configObj
);

module.exports = AnimalModel;

Now we can try to access the database. We won’t need a password for the database because the Lambda Function already has permissions from its Role.

// index.js
const AnimalModel = require("./animals");

const handler = async (event) => {

  // Create a model object
  const animal = new AnimalModel({
    id: "croc-1",
    name: "Larry",
    species: "crocodile"
  })

  // Save the model to the database
  const resp = await animal.save();

  // Create an HTTP response object
  const response = {
    statusCode: 200,
    body: JSON.stringify(`Hello from ${resp.name} the ${resp.species}.`)
  };

  return response;
};

module.exports = { handler };

You should get the results:

{"statusCode":200,"body":"\"Hello from Larry the crocodile\""}

And your data should be stored in the table called “cityZoo” in the cloud.

Using a script

You could put it all in a script, if you want.

#!/usr/bin/env zsh
# update-lambda
# This is just an example of a script you could use to update your lambda files
# It zips your JavaScript files and the node_modules directory, excluding some files.
# Then it saves it to the cloud as a Lambda Function called 'addToCityZoo'
# Finally, it runs and save the results to a file called 'lambda-results.txt' and prints it out.

rm lambda.zip

zip -r lambda.zip . -x lambda.zip lambda-results.txt update-lambda

aws lambda update-function-code --function-name addToCityZoo --zip-file fileb://build/lambda.zip

aws lambda invoke --function-name addToCityZoo --invocation-type RequestResponse lambda-results.txt

cat lambda-results.txt

You can visit this GitHub repo (see the branch minimal-dynamodb) for a working example of the code in this post.

In my next post, I’ll describe how to trigger this Lambda Function with a web request using AWS API Gateway.

Part 2 AWS API Gateway.

Thanks for reading!