# Create a Fast Node.js Serverless Backend Using AWS Lambda and DynamoDB

In this article, we'll build a simple CRUD JavaScript-based backend with AWS. We'll use Lambda and DynamoDB to show how you can quickly create a secure and robust app backend.

### Prerequisites

To follow this tutorial, you need an [AWS account](https://console.aws.amazon.com/console/home). Thankfully, AWS offers a twelve-months free tier plan (isn't that cool? 😜).

### Setting up the Lambda function

We'll use the [AWS console](https://us-east-1.console.aws.amazon.com/lambda/home?region=us-east-1#/functions) to create the Lambda function.

* Choose your preferred region (1), type ***Lambda*** in the search field near **Services** (2), then click on ***Lambda*** under **Services** in the result list (3).
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718141486999/317311fe-ac0e-4319-b6c7-476cca07141f.png align="center")

* On the **Lambda** dashboard, from the menu list on the left side, click on the ***Functions*** menu item (1), then click ***Create function*** (2).
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718142792106/137411a1-45fe-42e7-b62f-7c0661e40464.png align="center")

* On the **Create function** page, select ***Author from scratch*** (1), enter the ***Function name***: *sample-crud-func* (2), choose the ***Runtime***: *Node.js 20.x* (3), then under ***Change default execution role***, select *Create a new role with basic Lambda permissions* (4). Finally, click on the ***Create function*** button at the bottom.
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718144619495/74b6663b-2e8e-4748-b846-88ea12b22af5.png align="center")

* Once the function is ready, open the ***sample-crud-func*** function and test it.
    
    * Select the ***Test*** tab (1), then as the *Test event action*, choose the ***Create new event*** option (2). Provide the ***Event name***: *test* (3), then click the ***Test*** button.
        

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718408009397/3ea0c1b2-3d36-4e8e-968f-d967aef0c315.png align="center")

### Creating the DynamoDB table

The basic Lambda function is now ready. Before we add more logic to it, let's create the [DynamoDB](https://aws.amazon.com/dynamodb/) table for data storage.

DynamoDB is a fully managed, serverless NoSQL database service provided by AWS for modern applications. There are no upfront costs to launch DynamoDB, and you only pay for what you use.

* Go to the DynamoDB [page](https://us-east-1.console.aws.amazon.com/dynamodbv2/home?region=us-east-1#dashboard), and choose the ***region***. Here, we select us-east-1: N. Virginia (1). In the page menu, select ***Tables*** (2), then click on ***Create table*** button(3).
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718415423611/fbdfa4b5-c0ee-43ed-ad36-e71f2df7c2e0.png align="center")
    

* Provide the ***Table name*** (*sampleCrudTable*), type the ***Partition key*** (*pk*), and then the ***Sort key*** (*sk*). To keep things simple, use the default options and click ***Create table*** at the bottom of the page.
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718411033570/3c4c4ed6-fb31-4444-8ac6-fd561e8136ed.png align="center")

### Grant Lambda access to the DynamoDB table

* Let's open the *sample-crud-func* Lambda function, go to the ***Configuration*** (1) tab then in the *Execution role section*, click on ***Role name*** (2) to open the created named role.
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718414548036/6be68291-c32d-43a8-bac9-ca385dff3adf.png align="center")

* On the *sample-crud-xxx-role-xxx* (1) **role** page, open the ***Permissions*** tab (2), then click on the ***AWSLambdaBasicExecutionRole-xxx*** **policy name** (3).
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718416186958/412e8102-1ed1-4f6f-90e9-5d452034b149.png align="center")

* On the ***AWSLambdaBasicExecutionRole-xxx* policy** page, open the Permissions tab (1), then click on Edit (2).
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718416872935/580b6bc6-94a1-455b-b99d-1461ea2de88c.png align="center")

* In the ***Edit policy*** editor, add the below permission to the permissions list:
    
    ```json
            {
                "Effect": "Allow",
                "Action": [
                    "dynamodb:PartiQLInsert",
                    "dynamodb:PartiQLUpdate",
                    "dynamodb:PartiQLDelete",
                    "dynamodb:PartiQLSelect"
                ],
                "Resource": [
                    "arn:aws:dynamodb:us-east-1:xxx:table/sampleCrudTable"
                ]
            }
    ```
    
* Note: Remember to replace xxx with your AWS account number.
    
* Finally, the Policy editor should look like this:
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718418108359/0a7801e7-7930-44bd-834d-19fbe5646f7f.png align="center")

* Click on ***Next***, then ***Save changes*** to grant the CRUD [PartiQL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-gettingstarted.html) for DynamoDB statements permissions to the Lambda function.
    

### Perform a CRUD operation

* Head back to the Lambda function we created, open the ***code*** tab, and replace the content of the ***index.mjs*** file with the following code:
    

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

const client = new DynamoDBClient({});
const docClient = DynamoDBDocumentClient.from(client);

const ITEM_PK = "ITEM";

//-------SAVE ITEM FUNCTION-----------
const saveItem = async (tableName, data) => {
  const SK = ITEM_PK + "#" + data?.label; //format PK#label => manage default label sorting

  let result;
  try {
    const command = new ExecuteStatementCommand({
      Statement: `INSERT INTO ${tableName} value {'pk':?,'sk':?,'label':?, 'category':?, 'price':?}`,
      Parameters: [ITEM_PK, SK, data?.label, data?.category, data?.price],
    });

    result = await docClient.send(command);
  } catch (e) {
    console.error(JSON.stringify(e));
    return e;
  }

  return result;
};

export const handler = async (event) => {
  const tableName="sampleCrudTable";
  
  //Call save Item
  await saveItem(tableName, event)
    .then((res) => {
      console.log(JSON.stringify(res))
    })
    .catch((e) => {
      console.log(JSON.stringify(e.errorMessage));
    });
  
  const response = {
    statusCode: 200,
    body: JSON.stringify('Hello from Lambda!'),
  };
  return response;
};
```

* To test the function, open the ***Test*** tab, replace the ***Event JSON*** editor (1) content with the following code then click ***Test*** (2).
    

```json
{
  "label": "Paquet de Crayons de couleurs",
  "price": 30,
  "category": {
    "id": 1,
    "label": "Fourniture scolaire"
  }
}
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718420064390/93ea2eed-9163-496d-b94c-f9f0f587e50d.png align="center")

* Open the DynamoDB table, select ***Explore items*** (1) from the left menu, choose the ***sampleCrudTable*** table (2), and then click ***Run*** (3). You should see the created data (4).
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1718421072081/5a6a8642-0125-4c02-b599-d41536e9145b.png align="center")

In this article, we guided you through building a simple CRUD backend using AWS Lambda and DynamoDB. You learned how to set up a Lambda function, create a DynamoDB table, grant necessary permissions, and perform CRUD operations using JavaScript.

In the next articles, we'll learn how to secure and protect this backend using [API Gateway](https://aws.amazon.com/es/api-gateway/) and [Amazon Cognito](https://aws.amazon.com/pm/cognito).

Please subscribe and share. Thanks!
