Serverless Framework: Deploy a REST API using AWS Lambda and DynamoDB

Feb 27, 2019 · 5 min read

By Michele Riso


In my previous tutorial “Serverless Framework: Deploy an HTTP endpoint using NodeJS, Lambda on AWS” we learnt how to create an AWS Lambda HTTP endpoint, implemented in NodeJS, with Express using the Serverless framework.

Today we are going to learn how to:

  • Create and deploy a REST API with 2 endpoints (GET, POST) using Express, Serverless and AWS API Gateway
  • Provision a DynamoDB table using the Serverless syntax
  • Connect to the DynamoDB using the AWS SDK
Image for post
The architecture we aim to implement

Amazon DynamoDB is a fully managed NoSQL database service that provides fast and predictable performance with seamless scalability. —

Image for post
AWS DynamoDB

In a nutshell, DynamoDB is a serverless database for applications that need high performance at any scale.

So it sounds quite right to also use a serverless DB within a serverless application!


This tutorial takes into consideration that you already followed my previous tutorial and you are familiar with the basic concepts of the Serverless. If not or you want simply to refresh your mind, please have a look at “Serverless Framework: Deploy an HTTP endpoint using NodeJS, Lambda on AWS

Let’s start!

In my previous tutorial, It was fun to deploy an endpoint that was replying with a hard-coded “Hello Serverless!” message, however, this wasn’t very useful. Today we will see how we can persist data and retrieve it dynamically. We will, therefore, create a DynamoDB with a table in which we will store by .

Image for post

Configuring Serverless

Firstly, we need to configure Serverless in order to:

  • Give our Lambda read and write access to DynamoDB
  • Provision the table in the resources section

Start by copying the following code into our :

service: serverless-aws-nodejs-dynamodbcustom:
tableName: 'users-table-${self:provider.stage}'
name: aws
runtime: nodejs8.10
stage: dev
region: eu-central-1
- Effect: Allow
- dynamodb:Query
- dynamodb:Scan
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
- { "Fn::GetAtt": ["UsersDynamoDBTable", "Arn" ] }
USERS_TABLE: ${self:custom.tableName}
handler: app.server
- http:
path: /
method: ANY
cors: true
- http:
path: /{proxy+}
method: ANY
cors: true
Type: 'AWS::DynamoDB::Table'
AttributeName: userId
AttributeType: S
AttributeName: userId
KeyType: HASH
ReadCapacityUnits: 1
WriteCapacityUnits: 1
TableName: ${self:custom.tableName}

Note that we added 3 more sections this time:

  • : a custom section that we can use it to save any kind of configuration that we aim to reuse. In particular, we are saving the table name
  • : this section defines the permissions that our lambda function needs to interact with the AWS DynamoDB. For the scope of this tutorial, we gave the Lambda admin access. In real scenario remember to use the “least privilege” principle and always give the minimum permissions required
  • : in this section we can define, using CloudFormation syntax, the stack that AWS needs to use or creates if it does not exist already. In particular, we are defining and provisioning the User table. If you are not familiar with CloudFormation please have a look at the official documentation on Amazon website. AWS CloudFormation

Edit the server logic

After having defined our AWS stack, we need to modify the NodeJS App in order to:

  • Implement GET/POST endpoint: we will use GET to retrieve the user information and POST to create a new one
  • Interact with Dynamo DB

As the first step, we need to install the AWS SDK and . The AWS SDK is the official tool that enable us to interact with all the AWS services and components. Bodyparser is used to parse the body of HTTP requests

$ npm install --save aws-sdk body-parser

Now let’s copy the following code into the :

// app.js 
const sls = require('serverless-http');
const bodyParser = require('body-parser');
const express = require('express')
const app = express()
const AWS = require('aws-sdk');
const USERS_TABLE = process.env.USERS_TABLE;
const dynamoDb = new AWS.DynamoDB.DocumentClient();
app.use(bodyParser.json({ strict: false }));// Create User endpoint'/users', function (req, res) {
const { userId, name } = req.body;
const params = {
Item: {
userId: userId,
name: name,
dynamoDb.put(params, (error) => {
if (error) {
res.status(400).json({ error: `Could not create user ${userId}` });
res.json({ userId, name });
// Get User endpoint
app.get('/users/:userId', function (req, res) {
const params = {
Key: {
userId: req.params.userId,
dynamoDb.get(params, (error, result) => {
if (error) {
res.status(400).json({ error: `Could not get user ${userId}` });
if (result.Item) {
const {userId, name} = result.Item;
res.json({ userId, name });
} else {
res.status(404).json({ error: `User ${userId} not found` });
module.exports.server = sls(app)

We have removed the generic endpoint and added 2 new ones:

  • POST that we can use to create a new user
  • GET that we’ll use to retrieve the user provided its userId

For simplicity, we haven’t implemented any safety checks on the parameters of the requests. However, in a real-world scenario please keep in mind that you need to check at least the type (e.g. if the is a String). In the POST request you can also purify the parameters to avoid the most common attacks (e.g. using DOM PURIFY)


Let’s deploy it again with the already well-known command . The output is the same as before, however, this time Serverless has provisioned a DynamoDB as well.


Let’s try to create a new user using curl:

$ curl -X POST "" -d '{"userId":"micheleriso","name":"Michele Riso"}' -H "Content-Type: application/json"{"userId":"micheleriso","name":"Michele Riso"}%#THE OUTPUT

and then retrieve it:

$ curl -X GET "" -H "Content-Type: application/json"{"userId":"micheleriso","name":"Michele Riso"}% #THE OUTPUT

We have created a new user on DynamoDB! It’s really cool, isn’t? :-)


In this tutorial, we’ve learnt how to deploy a REST API Lambda function interconnect to DynamoDB using the Serverless Framework.

In the next tutorial, we will see how to run a local Lambda function connected to a local DynamoDB!

Here is a link to the bitbucket repo

Originally published at on February 27, 2019.

Gousto Engineering & Data Science

Gousto Engineering Blog

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store