Build a CRUD Rest API from Scratch with AWS API Gateway, Lambda and Dynamodb using Nodejs
Introduction
In this article we will focus in special AWS services who want to fast build and deploy endpoints, to GET/POST/PUT/DELETE information on a database regarding data of some application. The importance of server-less application are getting higher demand each day and aws available services offers a cheap and secured environment, so that the reason so many huge companies are migrating great part of their infrastructure to the cloud. We are using three awesome services API Gateway, Lambda and DynamoDB.
What is AWS API Gateway ?
Amazon API Gateway is a service provide by AWS that is used to create, publish, maintain, monitor & secure various API such as Rest APIs , HTTP & web socket at any scale. As an API developer you can create APIs that can access either AWS or any other web services along with the data store in the AWS cloud.
Lets start with Demo
Aim: To create an API with CRUD operation. Services Used -:
DynamoDB
Lambda
API gateway
IAM Service
Creating the DynamoDB Table
We will be using AWS DynamoDB a NoSQL database service to store data. DynamoDB is a fully managed, key-value, and document database that delivers single-digit-millisecond performance at any scale. Login to your AWS console and search for DynamoDB service.
Click on create table and enter table name, primary key always unique.
If you want to retrieve the data from dynamo db we should write the query to get the data by passing the key parameter.
If you want to retrieve the data you can retrieve it by using primary id.
I am creating table which save the user data: -
Table name : member_table
Partition key : MemberId (String)
Create a Role & Policy
Before we go for Lambda to be able to access DynamoDB we need to give Lambda permission. Let’s create a new Policy.
Open AWS Console, type IAM in the search bar, and hit enter.
you can create role.
After clicking create role select AWS service and choose the service as lambda and click on next.
In next page attach policy search for AMAzonDynamoDBFullAccess, api_excute, cloudfullacess, select that policy and click on next.
Enter role name and click create role.
Now attache this role to lambda function under the execution role select IAM role which you have created.
Create a Lambda Function
AWS Lambda is event-driven computing rather than an imperative model. Events-driven computing responds to events when the event source happens, it triggers the lambda function. The event source could be a request to an endpoint which we will go through later using API Gateway.
Search for lambda service
Double click on the lambda service and click on create function
There you select an author from scratch, give some function name and select the language as Nodejs
After selecting the required parameters click on create function. then you will be getting a code editor. there you write your nodejs code for get/put data from dynamo DB.
Function name: users_details_api
Runtime: Node.js 14.x
Execution role: Use an existing role
Role name: myServerlessRole
The handler method is the method that will be executed when the lambda function is invoked. This function takes in two objects, event and context.
The next code is already tested and it’s working
const AWS = require('aws-sdk');
AWS.config.update( {
region: 'ap-south-1'
});
const dynamodb = new AWS.DynamoDB.DocumentClient();
const dynamodbTableName = 'member_table';
const userPath = '/user';
const usersPath = '/users';
exports.handler = async function(event) {
console.log('Request event: ', event);
let response;
switch(true) {
case event.httpMethod === 'GET' && event.path === userPath:
response = await getUser(event.queryStringParameters.MemberId);
break;
case event.httpMethod === 'GET' && event.path === usersPath:
response = await getUsers();
break;
case event.httpMethod === 'POST' && event.path === userPath:
response = await saveUser(JSON.parse(event.body));
break;
case event.httpMethod === 'PATCH' && event.path === userPath:
const requestBody = JSON.parse(event.body);
response = await modifyUser(requestBody.MemberId, requestBody.updateKey, requestBody.updateValue);
break;
case event.httpMethod === 'DELETE' && event.path === userPath:
response = await deleteUser(JSON.parse(event.body).MemberId);
break;
default:
response = buildResponse(404, '404 Not Found');
}
return response;
}
async function getUser(MemberId) {
const params = {
TableName: dynamodbTableName,
Key: {
'MemberId': MemberId
}
}
return await dynamodb.get(params).promise().then((response) => {
return buildResponse(200, response.Item);
}, (error) => {
console.error('Do your custom error handling here. I am just gonna log it: ', error);
});
}
async function getUsers() {
const params = {
TableName: dynamodbTableName
}
const allUsers = await scanDynamoRecords(params, []);
const body = {
users: allUsers
}
return buildResponse(200, body);
}
async function scanDynamoRecords(scanParams, itemArray) {
try {
const dynamoData = await dynamodb.scan(scanParams).promise();
itemArray = itemArray.concat(dynamoData.Items);
if (dynamoData.LastEvaluatedKey) {
scanParams.ExclusiveStartkey = dynamoData.LastEvaluatedKey;
return await scanDynamoRecords(scanParams, itemArray);
}
return itemArray;
} catch(error) {
console.error('Do your custom error handling here. I am just gonna log it: ', error);
}
}
async function saveUser(requestBody) {
const params = {
TableName: dynamodbTableName,
Item: requestBody
}
return await dynamodb.put(params).promise().then(() => {
const body = {
Operation: 'SAVE',
Message: 'SUCCESS',
Item: requestBody
}
return buildResponse(200, body);
}, (error) => {
console.error('Do your custom error handling here. I am just gonna log it: ', error);
})
}
async function modifyUser(MemberId, updateKey, updateValue) {
const params = {
TableName: dynamodbTableName,
Key: {
'MemberId': MemberId
},
UpdateExpression: `set ${updateKey} = :value`,
ExpressionAttributeValues: {
':value': updateValue
},
ReturnValues: 'UPDATED_NEW'
}
return await dynamodb.update(params).promise().then((response) => {
const body = {
Operation: 'UPDATE',
Message: 'SUCCESS',
UpdatedAttributes: response
}
return buildResponse(200, body);
}, (error) => {
console.error('Do your custom error handling here. I am just gonna log it: ', error);
})
}
async function deleteUser(MemberId) {
const params = {
TableName: dynamodbTableName,
Key: {
'MemberId': MemberId
},
ReturnValues: 'ALL_OLD'
}
return await dynamodb.delete(params).promise().then((response) => {
const body = {
Operation: 'DELETE',
Message: 'SUCCESS',
Item: response
}
return buildResponse(200, body);
}, (error) => {
console.error('Do your custom error handling here. I am just gonna log it: ', error);
})
}
function buildResponse(statusCode, body) {
return {
statusCode: statusCode,
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(body)
}
}
Click on the Deploy button to deploy the Lambda function.
Create an API Gateway
When your API method receives an HTTP request, API Gateway invokes your Lambda function.
Create a REST API in API Gateway.
Open AWS Console, type API Gateway in the search bar, and hit enter.
Click on the Build button on REST API.
Fill in the details as below.
Choose the protocol: REST
Create new API: New API
API name: user-api
Endpoint Type: Regional
Select the Actions drop-down list, choose to Create Resource. Fill in the details as below.
Resource Name: users
Second Resource Name : user
Click on Create Resource button to complete. Select the Actions drop-down list again, choose Create Method. Select POST to insert a new record. Again repeat process for all methods Get, Update, Delete
Integration type: Lambda Function
Use Lambda Proxy integration: Checked(remember to check so event details will be passed to Lambda)
Lambda Function: users_details_api
Click the Save button, a message with Add Permission to Lambda Function will pop out, click OK to grant the permission.
Deploy the API
In the last step, we need to deploy the API so that we can access it thru the public. Click on the Actions drop-down list, select Deploy API.
Click the Deploy button and then the Save Changes button. An Invoke URL will appear on top. Try accessing the URL from the browser or Postman.
Test API using Postman
Copy the Invoke URL and paste in Postman Paste the test data to Request Body and click send.
{ "Name": "Ashu", "Last Name": "V", "Gender": "Male", "phone_number" : "9898989898" }
Verify the data in the DynamoDB table.
In conclusion, we have learned about creating a serverless CRUD API using AWS services such as Lambda, DynamoDB, and API Gateway.
You can Watch YouTube Video