Build a Todo list with AWS Lambda and DynamoDB
Tags: serverless, aws, node, tutorial
Published: 2022-11-29 09:40:12

In this post we will be building simple CRUD API to manage tasks and in the upcoming posts we will use this project as a base to explore other AWS services.

But in order to follow along with this post you need to have a basic understanding of [DynamoDB](https://dev.to/ckmonish2000/intro-to-dynamodb-with-node-keb) and how to setup your [lambda function](https://dev.to/ckmonish2000/intro-to-serverless-framework-iac-101-471i) and [DynamoDB database](https://dev.to/ckmonish2000/how-to-setup-dynamodb-with-serverless-framework-3c95) using the serverless framework.

So, let's begin


## Project structure

The code is structured using a service-oriented approach where we basically follow a 3-layer architecture.

The main advantage of using the 3-layer-architecture is that it creates a level of abstraction and allows you to manage your code base more efficiently.

![service-oriented architecture] (https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vhvzppwzm40mykfqwl8r.png)


So, create a folder called `src` and create 3 files:

- `functions.js` - which basically is your controller
- `io.js` - which will be your service layer
- `model.js` - which will be your data access layer


## Tips

Before we start just want to drop in few serverless commands that will speed up your deployment and debugging process.


1. serverless deploy function --function functionName

2. serverless logs -f functionName -t

The first command allows you to only deploy a single function rather than your entire infrastructure.

The second command allows you to view the logs for a given function.

## Database operations

Now in the `model.js` file we will define all the operations we will be performing on the todo table.

In the code below I'm creating a class called Todo which will contain the respective methods `fetchAll` `fetchById` `put` `deleteById`.

You can follow the [DynamoDB 101](https://dev.to/ckmonish2000/intro-to-dynamodb-with-node-keb) post to understand how it works

```
const aws = require('aws-sdk');

class Todo {
  client = new aws.DynamoDB.DocumentClient();
  TableName = "todoTable"

  async put(Item) {
    const params = {
      TableName: this.TableName,
      Item
    }
    const result = await this.client.put(params).promise()

    return true
  }


  async fetchById(key) {
    const params = {
      TableName: this.TableName,
      Key: {
        userId: key
      }
    }
    const result = await this.client.get(params).promise()
    return result.Item
  }

  async fetchAll(key) {
    const params = {
      TableName: this.TableName,
    }
    const result = await this.client.scan(params).promise()
    return result.Items
  }

  async deleteById(key) {
    const params = {
      TableName: this.TableName,
      Key: {
        userId: key
      }
    }
    const result = await this.client.delete(params).promise()
    return true
  }
}

module.exports = new Todo();
```

## Service layer 

This layer will basically encapsulate your business logic since this is a basic todo app we'll just extract the body and rout parameter from the request and return it.

```
module.exports = {
  input: (event) => JSON.parse(event.body),
  params: (event) => event.pathParameters
}
```


## Controller

This section of the project will contain all your function logic that we'll link in the `serverless.yml` file in a sec.

if you're not sure how to write your functions checkout the post on [serverless functions for dummies](https://dev.to/ckmonish2000/serverless-functions-for-dummies-2aae)

```
'use strict';
const io = require('./io')
const Todo = require('./model')

const getAllTasks = async (event) => {
  const data = await Todo.fetchAll();
  return data
};


const taskById = async (event) => {
  const { id } = io.params(event)
  const data = await Todo.fetchById(id);
  return data
}

const createTask = async (event) => {
  const body = io.input(event);
  const data = await Todo.put(body)
  return JSON.stringify({ message: "created task" })
}

const updateTask = async (event) => {
  const body = io.input(event);
  const data = await Todo.put(body)

  return JSON.stringify({ message: "updated task" })
}

const deleteTask = async (event) => {
  const { id } = io.params(event)
  const data = await Todo.deleteById(id);
  return JSON.stringify({ message: "deleted task with id = " + id })
}


module.exports = {
  getAllTasks,
  taskById,
  createTask,
  updateTask,
  deleteTask
}
```

## Serverless config

Try to setup the serverless configs on your own, the below code is just for your reference.


```
'use strict';
const io = require('./io')
const Todo = require('./model')

const getAllTasks = async (event) => {
  const data = await Todo.fetchAll();
  return data
};


const taskById = async (event) => {
  const { id } = io.params(event)
  const data = await Todo.fetchById(id);
  return data
}

const createTask = async (event) => {
  const body = io.input(event);
  const data = await Todo.put(body)
  return JSON.stringify({ message: "created task" })
}

const updateTask = async (event) => {
  const body = io.input(event);
  const data = await Todo.put(body)

  return JSON.stringify({ message: "updated task" })
}

const deleteTask = async (event) => {
  const { id } = io.params(event)
  const data = await Todo.deleteById(id);
  return JSON.stringify({ message: "deleted task with id = " + id })
}


module.exports = {
  getAllTasks,
  taskById,
  createTask,
  updateTask,
  deleteTask
}
```

now run `serverless deploy` and try out your apis using postman.