AWS Serverless stack - API Gateway, Lambda and DynamoDB

in Node.JS, AWS

Hi. I've recently written an article about Claudia API Builder and AWS Lambda and it got a lot of views. You can check it here: http://ivanjov.com/building-serverless-api-with-claudia-api-builder/. If you haven't read it, now's the time, you will need to understand what is Claudia API Builder and AWS Lambda before going through this article.

Today I want to talk about how can we use a database in Claudia API Builder and make an awesome serverless stack. Since we are using AWS Lambda service, in this article we are going to stick to AWS and use DynamoDB.

What is DynamoDB?

AWS DynamoDB is a fully managed NoSQL database service that provides fast and predictable performance with seamless scalability. DynamoDB scales automatically and you don't have to worry about hardware provisioning, setup, and configuration, software updates or anything like that.

With DynamoDB, you can create database tables that can store and retrieve any amount of data, and serve any level of request traffic. This is great because AWS Lambda gives us that feature too, we can have unlimited traffic and it will always work and respond to events.

You can scale up or scale down your tables' throughput capacity without downtime or performance degradation, and use the AWS Management Console to monitor resource and performance metrics. It's pretty awesome!

Setting up the project

Let's start. For setting up, you will need to have AWS account and ability to create Lambda function and DynamoDB table. We are going to build a Book database, with three operations:

  1. Add new book
  2. Get book by ID
  3. Delete book from database

Pulling code from Github

I have already written code and you can pull it from Github repo:

git clone https://github.com/IvanJov/claudia-api-builder-dynamo-db-example.git && cd claudia-api-builder-dynamo-db-example

This command will pull the code from repo and it will open the folder with code.

You will also need to install all dependencies:

npm install

Creating DynamoDB table

Let's create a DynamoDB table. Open your AWS Console using this link: https://console.aws.amazon.com/dynamodb/home

Find Create table section at the top of the page:

Click on Create table. You should see this:

Fill the Table name field. That's the name of the table that we will use. I named it claudia-api-builder-example but you can use some other (and remember it, we will need to connect our Lambda code with it later). And fill Primary key. For this example, it should be bookId, an ID for our book. Also select Number from the dropdown, because we are going to use the number as an ID.

Click on Create. That's all from our side. Please wait until your table is created. After it's created, continue with the article.

Main logic

Main logic is in index.js file. At the top, we are including all dependencies. We also need to initialize api object and export it:

var ApiBuilder = require('claudia-api-builder'),
  AWS = require('aws-sdk'),
  api = new ApiBuilder(),
  dynamoDb = new AWS.DynamoDB.DocumentClient();

module.exports = api;

As you can see, we aren't entering any credentials, all those stuff are handled by Claudia.js.

We also need to have one line of code at the bottom:

api.addPostDeployConfig('tableName', 'DynamoDB Table Name:', 'configure-db');

This code sends us a prompt DynamoDB Table Name: after the deployment process. That's important because Claudia.JS saves table name and we can access it in every request. We can access it in every request, in request object: request.env.tableName.

Book creation

Next block of code handles book creation and it looks like this:

api.post('/book', function (request) {
  'use strict';
  var id = request.body.bookId;
  var params = {
    TableName: request.env.tableName,
    Item: {
      bookId: id,
      name: request.body.name,
      author: request.body.author,
      genre: request.body.genre
    }
  };

  return dynamoDb.put(params).promise()
    .then(function () {
      return 'Created book with id ' + id;
    });
}, { success: 201 });

It handles POST requests that are sent to /book endpoint. We are taking table name from request.env.tableName and book information from the body of the request. As you can see, we are sending name, author and genre. DynamoDB saves that, API returns 201 success code and a success message.

Example:

If you send new POST request with same bookId, DynamoDB will update book with that ID with new data.

Getting book by ID

Code bellow handles reading from DB by ID.

api.get('/book/{id}', function (request) {
  'use strict';

  var params = {
    TableName: request.env.tableName,
    Key: {
      bookId: parseInt(request.pathParams.id)
    }
  };

  return dynamoDb.get(params).promise()
    .then(function (response) {
      return response.Item;
    });
});

It handles GET requests that are sent to /book/{id} endpoint.

We are creating params object with our book id and table name. dynamoDb.get(params).promise() returns a Promise with a response. Everything else is handled by the Claudia (converting the response to JSON, returning data...)

Example:

Deleting book

api.delete('/book/{id}', function (request) {
  'use strict';
  var id = parseInt(request.pathParams.id);
  var params = {
    TableName: request.env.tableName,
    Key: {
      bookId: id
    }
  };

  return dynamoDb.delete(params).promise()
    .then(function () {
      return 'Deleted book with id ' + id;
    });
}, {success: { contentType: 'text/plain'}});

It handles DELETE requests that are sent to /book/{id} endpoint. It's almost same as our GET request above. We also have Promise returned with a simple string message.

Example:

Deploying

As you know, deployment with Claudia.js is simple. package.json already contains scripts that we can use for deployment:

  • create - use it only once, when you deploy your code for the first time
  • deploy - use it every time when you want to deploy new code
  • reconfigure - use it when you want to change the configuration of your table (change table for example).

For deploying our code, use this command:

npm run create

At the end of the deployment process, you will be asked to provide table name:

DynamoDB Table Name:

Just insert the table name you put in Table name field when you created your DynamoDB table and press Enter.

Next time when you want to update your code, use:

npm run deploy

Conclusion

API Gateway, Lambda, and DynamoDB are awesome services. When they are combined, they can be an awesome stack that's easy to use, cheap and easy to get started with. In combination with Claudia, you can create services that will be available at any time and process the unlimited number of requests. Pretty awesome!

Comments