Build CRUD API with AWS Lambda and DynamoDB
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 and how to setup your lambda function and DynamoDB database 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] (dev-to-uploads.s3.amazonaws.com/uploads/art..)
So, create a folder called src
and create 3 files:
functions.js
- which basically is your controllerio.js
- which will be your service layermodel.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.
serverless deploy function --function functionName
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 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
'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.