DynamoDB CRUD with NodeJS and Lambda
Tags: node, devops, dynamodb, restapi
Published: 2020-08-30 11:54:25

AWS defines DynamoDB as "Amazon DynamoDB is a key-value and document database that delivers single-digit millisecond performance at any scale. It's a fully managed, multiregion, multimaster, durable database with built-in security, backup and restore, and in-memory caching for internet-scale applications". So from the definition, it is clear that DynamoDB is a serverless, fully-managed millisecond performance and highly scalable NoSQL database which was announced in Early 2012.

In this article, we'll perform basic CRUD operations using AWS Lambda and NodeJS. To kick off, we first have to define the following file structure:

![dynamocrud.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1597676042852/Y8KEZD7Jc.png)

we'll call our root-folder DynamoCRUD, however feel free to call it anything you like. Under our root folder, we'll create a folder called resources which will contain a file called dynamo-table.yml containing our code for creating DynamoDB table. Also since we'll be using Serverless Framework to deploy our cloudformation stack, i assume that you already have installed and set up the programmatic access to your AWS account with Serverless. If not you can refer to the  [Serverless Documentation](https://www.serverless.com/framework/docs/providers/aws/guide/installation/) .
After creating a folder called resources, we'll generate a template using serverless framework with the command:

```
sls create -t aws-nodejs
``` 
This will generate the serverless.yml file, handler.js file and .gitignore file and finally our file structure will be completed.

Now, lets get started with our serverless.yml file. Our serverless.yml file will look like this:

```
service: DynamoCRUD

provider:
  name: aws
  runtime: nodejs12.x
  profile: default
  timeout: 30

  iamRoleStatements:
    - Effect: "Allow"
      Action:
        - "dynamodb:*"
      Resource: "*"

functions:
  addItem:
    handler: handler.addItem

  getAllItem:
    handler: handler.getAllItem
  
  updateItem:
    handler: handler.updateItem

  deleteItem:
    handler: handler.deleteItem

resources:
  - ${file(resources/dynamo-table.yml)}
``` 
So basically what we're doing is we're creating a dynamoDB table using resources section and creating 4 basic functions to perform the CRUD operation and giving DynamoDB permission to our Lambda functions.

Now, we'll create a DynamoDB table i.e. our dynamo-table.yml under resources folder. It will look something like :

```
Resources:
  myDynamoDBTable:    # Logical Id of the resource
    Type: AWS::DynamoDB::Table

    Properties:
      AttributeDefinitions:
        - 
          AttributeName: "year"
          AttributeType: "N"
        - 
          AttributeName: "title"
          AttributeType: "S"

      KeySchema:
        - AttributeName: "year"    # Partition Key
          KeyType: "HASH"
        - AttributeName: "title"    # Sort Key
          KeyType: "RANGE"

      TableName: "Movies"     

      ProvisionedThroughput:   # Optional, can be skipped
        ReadCapacityUnits: 10
        WriteCapacityUnits: 10

``` 

So basically we're creating a table with the above attribute definitions.

Now, lets write our handler.js file. This will have the code for all the CRUD operation defined on serverless.yml file.


```
"use strict";
const AWS = require('aws-sdk');

const docClient = new AWS.DynamoDB.DocumentClient();

// Function to Create an Item to DB
module.exports.addItem = async (event) => {
  try {

    let table = "Movies";
    let year = 2015;
    let title = "The Big New Movie";

    let params = {
      TableName: table,
      Item: {
        "year": year,
        "title": title,
        "info": {
          "plot": "Nothing happens at all",
          "rating": 0
        }
      }
    }

    let result = await docClient.put(params).promise();
    if (result) {
      console.log(">>>>>>>>>", result);
    }
   
    console.log("hello world")
    return {
      statusCode: 200,
      body: JSON.stringify({
        message: "Go Serverless v1.0! Your function executed successfully!",
        data: result
      }),
    };
  } catch (error) {
    console.log(error);
    return error;
  }
};

// Function to getAllItems from DB
module.exports.getAllItem = async () => {
  let table = "Movies";
  let year = 2015;

  let title = "The Big New Movie";

  let params = {
    TableName: table,
    Key: {
      "year": year,
      "title": title
    }
  }

  try {
    let result = await docClient.get(params).promise();

    console.log(result);

    return {
      body: JSON.stringify({
        message: "Executed succesfully",
        data: result
      })
    }
  } catch (error) {
    console.log(error);
  }
}

// Function to update an Item in DB
module.exports.updateItem = async () => {
  let table = "Movies";
  let year = 2015;

  let title = "The Big New Movie";

  let params = {
    TableName: table,
    Key: {
      "year": year,
      "title": title
    },
    UpdateExpression: "set info.rating = info.rating + :val",
    ExpressionAttributeValues: {
      ":val": 1
    },
    ReturnValues: "UPDATED_NEW"
  };

  try {
    let result = await docClient.update(params).promise();
    return {
      body: JSON.stringify({
        message: "updated succesfully",
        data: result
      })
    }
  } catch (error) {
    console.log(error);
  }
}

// Function to Delete an item
module.exports.deleteItem = async () => {

  let table = "Movies";
  let year = 2015;

  let title = "The Big New Movie";

  let params = {
    TableName: table,
    Key: {
      "year": year,
      "title": title
    }
  }

  let result = await docClient.delete(params).promise();

  return {
    body: JSON.stringify({
      message: "deleted succesfully",
      data: result
    })
  }

}
``` 
One thing to note here, I'm hard-coding the Data to be created in DB for the sake of simplicity. Feel free to change the AddItem method into POST and parse the body from event.body, you can totally do that. Same goes for update and delete method. I'm just trying to keep the things as simple as possible.

Now, the last thing to do is deploy our stack to AWS and we'll be ready to test our functions worked or not. To deploy the stack simply just enter the following command:


```
sls deploy -v
``` 

This will return all the functions end-point. You can use POSTMAN to to hit the end-points and check the responses.


> Thanks for Reading