REST API Using AWS API Gateway, Lambda and DynamoDB
By: Souvik Paul
Tags: Nodejs, AWS Lambda, Curl, Api Gateway, Dynamodb

Objective

Our objective is to create a simple REST API using Amazon API gateway, Lambda and DynamoDB. Here, user will make calls to the API end-point, which will be received by API gateway. Then, API gateway forwards the request to the Lambda function, where it is processed and accordingly it performs operations on DynamoDB.

What is API?

According to Redhat, an API is a set of definitions and protocols for building and integrating application software. API stands for application programming interface.

APIs let your product or service communicate with other products and services. This simplifies application development, saving time and cost.

Amazon API Gateway

AWS API gateway is a fully managed service that makes it easy for developers to create, publish, maintain, monitor and secure APIs. API acts as a front door for the application to access data, business logic or functionality from the backend services. It handles all the task involved in accepting and processing up of hundreds or thousands of concurrent API calls, including traffic management, authorization, access control, monitoring and API management.

AWS Lambda

AWS lambda lets the user to run code without provisioning or managing servers and the user needs to pay for how much they use. The user can also scale it up and down according to their needs.

Amazon DynamoDB

Amazon DynamoDB is a fully managed proprietary NoSQL database service that supports key-value and document data structures. It allows us to create database tables that can store and retrieve any amount of data. It also relieves the customers from the burden of operating and scaling a distributed database.

So, now it’s time to start creating the API.

Prerequisites -

You should have an AWS account. You should have a basic knowledge of Node.js. Postman or CURL should be installed in your system.

Step 1: Go to DynamoDB console and click on Create table and the enter the table name as myDB and the primary key as id whose type will be string. This will be our only key for this project. All the remaining settings in that page will be left untouched and then we’ll click on create to create the table. After the table is created, we’ll get an Amazon Resource Name (ARN) which will look like the following —

arn:aws:dynamodb:ap-south-1:123456789023:table/myDB

Note that 123456789023 will be the AWS account ID, which will be unique for everybody.

Step 2: Now we’ll create an IAM access policy with JSON to grant the required permissions to the DynamoDB table and CloudWatch Logs. We will attach this policy to a role, and this role will then be attached to a Lambda function, which will assume the required access to DynamoDB and CloudWatch Logs.

Now, we’ll go to IAM console and click on Policies and then click on create policy. We’ll choose JSON where we’ll enter the following in the editor.

{

"Version": "2012-10-17",

"Statement":[{

"Effect": "Allow",

"Action": [

"dynamodb:BatchGetItem",

"dynamodb:GetItem",

"dynamodb:Query",

"dynamodb:Scan",

"dynamodb:BatchWriteItem",

"dynamodb:PutItem",

"dynamodb:UpdateItem"

],

"Resource": "arn:aws:dynamodb:ap-south-1:123456789023:table/myDB"

},

{

"Effect": "Allow",

"Action": [

"logs:CreateLogStream",

"logs:PutLogEvents"

],

"Resource": "arn:aws:logs:ap-south-1:123456789023:*"

},

{

"Effect": "Allow",

"Action": "logs:CreateLogGroup",

"Resource": "*"

}

]

}

After that we’ll click on Review policy and then enter the name of the policy as policy_for_LambdaDdbApi and then click on Create policy.

Now , let’s understand the above policy. The first element in this policy is the Version , which defines the JSON version that we’re using. The next element is Statement , which is the main section of the policy and includes multiple elements.

Effect element — Specifies whether the statement results in an Allow or an explicit Deny . By default, access to resources is implicitly denied. In this example, we have used Allow because we want to allow the actions.

element — Specifies whether the statement results in an or an explicit . By default, access to resources is implicitly denied. In this example, we have used because we want to allow the actions. Action element — Describes the specific actions for this statement. Each AWS service has its own set of actions that describe tasks that we can perform with that service. We have used the DynamoDB actions that we want to allow. For the definitions of all available actions for DynamoDB, see the DynamoDB API Reference.

element — Describes the specific actions for this statement. Each AWS service has its own set of actions that describe tasks that we can perform with that service. We have used the DynamoDB actions that we want to allow. For the definitions of all available actions for DynamoDB, see the DynamoDB API Reference. Resource element — Specifies the object or objects for this statement using Amazon Resource Names (ARNs). We use an ARN to uniquely identify an AWS resource. To build the Resource element for DynamoDB, we have to specify the AWS service ( dynamodb ), AWS Region ( ap-south-1 ), AWS account ID ( 123456789023 ) and table ( table/myDB ).

In this policy, we’ve created a second statement to allow access to CloudWatch Logs so that the Lambda function can write log files for troubleshooting and analysis. We’ve used the same elements as for the DynamoDB statement, but have changed the following values:

For the Action element, we’ve used the CloudWatch actions that we want to allow. Definitions of all the available actions for CloudWatch are provided in the CloudWatch API Reference.

element, we’ve used the CloudWatch actions that we want to allow. Definitions of all the available actions for CloudWatch are provided in the CloudWatch API Reference. For the Resource element, we’ve specified the AWS account to which we want to allow my Lambda function to write its log files. As in the preceding example for DynamoDB, we have to use the ARN for CloudWatch Logs to specify where access should be granted. To build the Resource element for CloudWatch Logs, we have to specify the AWS service ( logs ), AWS Region ( ap-south-1 ), AWS account ID ( 123456789023 ) and all log groups in this account ( * ).

We also created a third statement to allow access to CloudWatch Logs so that the Lambda function can create a log group. This is required because the logs:CreateLogGroup action supports only wildcard element names. We used the same elements as for the DynamoDB statement, but changed the following values:

For the Action element, we’ve used the CloudWatch actions that I want to allow. Definitions of all the available actions for CloudWatch are provided in the CloudWatch API Reference .

element, we’ve used the CloudWatch actions that I want to allow. Definitions of all the available actions for CloudWatch are provided in the CloudWatch API Reference . For the Resource element, we’ve used a wildcard character (“ * “) because the logs:CreateLogGroup action supports only wildcard element names.

Step 3: Now, in the IAM console, click on Roles and then Create roles. This role will be created for Lambda function. So, select Lambda from the service selection section. the we’ll search for the policy name that we’ve just created, i.e, policy_for_LambdaDdbApi and attach it to a role whose name will be role_for_LambdaDdbApi.

Step 4: Now, we’ll create the Lambda function. We’ll go to Lambda console and click on create function. Select Author from scratch. We’ll give our function a name funcLambdaDdbApi. runtime will be selected as node.js12.x. In the permission field, select Use an existing role and then from the dropdown menu select role_for_LambdaDdbApi. By doing this, we’ve integrated the DynamoDB table with the Lambda function.Now, click on create function and write the function code as follows and deploy it.

When a user sends a request, he is required to mention the following in the request body -

operation — what operation he wants to perform on the database.

— what operation he wants to perform on the database. tableName — in which table he wants to perform the operation.

— in which table he wants to perform the operation. payload — what data he wants to insert or read from the table.

Above three things will be parsed by our lambda function and will perform the tasks as defined in it.

Step 5: Now, we have to integrate API gateway with this lambda function. We’ll go to API Gateway console and click on Create REST API. We’ll enter API name as api_for_lambdaDdbAPi. Remaining options will be left untouched and then we’ll click on Create API. Then from the Actions dropdown menu, select create resource. Enter resource name as myresource and then click on Create resource. Then, again from the Actions dropdown menu, select Create Method. We’ll select POST method. In this method, integration type will be Lambda function. In the Lambda function name field, we’ll enter funcLambdaDdbApi, so as to integrate our lambda function with this API gateway. Remaining fields will be left unchanged. Then, click save. Now, we’ll deploy this API. From the Actions dropdown menu, select deploy API and enter deployment stage as [new stage] and stage name as Test. Finally, click on deploy. We’ve to take a note of the invoke URL that we get after deployment, which will look like the following —

https://xt657hawc4.execute-api.ap-south-1.amazonaws.com/test

Step 6: Now, our project is operational and we’ll test it using CURL. We’ll open the terminal and run the following two commands —

curl -X POST -d '{"operation":"create","tableName":"myDB","payload":{"Item":{ "id":"1", "name":"Maverick", "movie":"Top Gun" }}}' https://xt59h6awc4.execute-api.ap-south-1.amazonaws.com/test/myresource curl -X POST -d '{"operation":"create","tableName":"myDB","payload":{"Item":{ "id":"2", "name":"Tom Cruise" }}}' https://xt59h6awc4.execute-api.ap-south-1.amazonaws.com/test/myresource

Now, we’ll go to DynamoDB console and we’ll see that our payload has been entered into the table.

Please note that, DynamoDB does not require schema definition, and so there is no such thing called as a “column”. We can just add a new item with a new attribute.

Now, we’ll perform read operation. For that, run the following commands.

curl -X POST -d '{"operation":"read","tableName":"myDB","payload":{"Key":{ "id":"1" }}}' https://xt59h6awc4.execute-api.ap-south-1.amazonaws.com/test/myresource

Output -

curl -X POST -d '{"operation":"read","tableName":"myDB","payload":{"Key":{ "id":"2" }}}' https://xt59h6awc4.execute-api.ap-south-1.amazonaws.com/test/myresource

Output -

Summary

In this article, we have discussed Amazon API Gateway, AWS lambda, Amazon DynamoDB and finally, we’ve created a REST API using all the three AWS services.

References: