Serverless API with DynamoDB, using AWS Lambda

This tutorial shows how to create a serverless API with DynamoDB using Claudia API Builder.

Prerequisites

The goal is to show how to create a serverless Node.js app with DynamoDB that stores and retrieves data. This service will be for an ice cream shop. You will save and show ice creams.

The overview of your service infrastructure

1. Serverless host setup — AWS

You need to have an AWS account with a locally set AWS credentials file, and installed Claudia.js .

If you don’t have it, please go through Installing and Configuring Claudia.js.

2. Write your service — Ice Cream Shop

Create your project folder (you can name it ice-cream-shop) and open it in your terminal. 

Initialize your Node project.

You can do it quickly by running npm init -f

Then run

npm install aws-sdk claudia-api-builder -S 

This installs AWS SDK and Claudia API Builder. You need AWS SDK for accessing DynamoDB. Claudia API Builder is a helper tool with an Express-like syntax for your endpoints.

Your service needs to have two endpoints:

  1. to save an icecream — needs a POST request

  2. to get all saved ice creams — needs a GET request

Now create an empty index.js file. Open it and type:

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

api.post('/icecreams', function (request) { // SAVE your icecream
  var params = {  
    TableName: 'icecreams',  
    Item: {
        icecreamid: request.body.icecreamId,
        name: request.body.name // your icecream name
    } 
  }
  return dynamoDb.put(params).promise(); // returns dynamo result 
}, { success: 201 }); // returns HTTP status 201 - Created if successful

api.get('/icecreams', function (request) { // GET all users
  return dynamoDb.scan({ TableName: 'icecreams' }).promise()
      .then(response => response.Items)
});

module.exports = api;

This finishes your service.

3. Database — setup DynamoDB

You need to create a database on AWS, but instead of using AWS Console, you can just execute one command:

aws dynamodb create-table --table-name icecreams \
  --attribute-definitions AttributeName=icecreamid,AttributeType=S \
  --key-schema AttributeName=icecreamid,KeyType=HASH \
  --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1 \
  --region us-east-1 \
  --query TableDescription.TableArn --output text

This command creates a DynamoDB table named icecreams in the same region as our Lambda, with an key attribute icecreamid of String type. The command returns the table’s Amazon Resource Name (ARN) to confirm that everything is set up correctly.

Giving your service permission for the database

The last step is allowing your service access to your DynamoDb database. To do that your service requires a permission policy. Instead of doing it via AWS Console, you can create a policy file in your project and apply it with Claudia.

Inside your ice-cream-shop project folder create a folder named policy and in it a file called dynamodb-policy.json with the following contents:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "dynamodb:DeleteItem",
        "dynamodb:GetItem",
        "dynamodb:PutItem",
        "dynamodb:Scan"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}

This policy allows your Lambda service to access your DynamoDb database. When invoking Claudia to deploy your code, this policy file location needs to be passed as the command option, to let Claudia know to assign the policy to your Lambda.

It’s time for your first deployment. In the first, Claudia.js creates a Lambda for your service. So, go back to your project folder ice-cream-shop and run:

claudia create --region us-east-1 --api-module index --policies policy

This command creates your serverless container (AWS Lambda) in the us-east-1 region, sets the index file as the main, and assigns the policy from the policy folder to your Lambda. If successful, it returns the created service URL endpoint in the command final output similar to this:

{
  "lambda": {
    "role": "ice-cream-shop-executor",
    "name": "ice-cream-shop",
    "region": "us-east-1"
  },
  "api": {
    "id": "your-service-id",
    "module": "index",
    "url": "https://your-service-url.execute-api.us-east-1.amazonaws.com/latest"
  }
}

That’s it! 

Trying out your service

Use cURL for testing. Get all ice creams:

curl https://your-service-url.execute-api.us-east-1.amazonaws.com/latest/icecreams

Save an ice cream:

curl -H "Content-Type: application/json" -X POST \
-d '{"icecreamId":"123", "name":"chocolate"}' \
https://your-service-url.execute-api.us-east-1.amazonaws.com/latest/icecreams

By running these commands you’ll see your service working!

That’s it!

Errors?

In case of an error, please check your code if you haven’t missed anything. After an error, invoking the command again may show

'Role with name ice-cream-shop-executor already exists.'

In that case, go to your AWS Console IAM, in the left bar click Roles and find a role with the name error specified and delete it. Then try the previous claudia create command again.

Updating your service

If you want to redeploy to your Lambda with Claudia.js, now you need to do a claudia update instead of create . The full command would look like this:

claudia update

It doesn’t need all those configuration options like create, because it stores them locally for you. If its successful, it also returns the URL of your deployed service.

Now go, you deserve some ice cream!

Did you like this tutorial? Get notified when we publish the next one.

Once a month, high value mailing list, no ads or spam. (Check out the past issues)