Node-Express-Typescript Services as AWS Lambda function with AWS DynamoDB and DynamoDB Local

This tutorial walks you, step by step, through setting up services layer using NodeJS with Express and Typescript and be able to run as AWS Lambda function. It starts out with setting up basing service. Secondly, it shows how to use AWS DynamoDBto as database layer. After that it shows how to run this service layer as AWS Lambda function. Lastly it shows how to make use of DynamoDB Local for development without incurring cost of reading and writing to DynamoDB.

So lets start with creating a folder named “serverlessNodeExpressServices”.

Open command prompt/power shell/ bash shell in this folder.

Run “npm init” in this directory

Follow the prompts to create basic NodeJS middleware project. You can choose defaults.

Enter “yes” to save the configuration:

It would create a package.json file

Now install the following dependencies necessary for NodeJS backend services:

“npm install @types/node angular2-template-loader awesome-typescript-loader compression cors css-loader express extract-text-webpack-plugin file-loader html-webpack-plugin minimist node-sass pug raw-loader sass-loader style-loader tslint typescript url-loader webpack webpack-dev-server — save”

Now install dependencies needed to interact with AWS services and running it as serverless:

“npm install aws-sdk aws-serverless-express — save”

After these dependencies are installed, your package.json should look similar to the following:

package.json with all dependencies

Now open the project in Visual Studio Code (or any other editor of your choice). Create a folder ‘src’ and create a file- ‘app.ts’.

Add the following code to ‘app.ts’:

app.ts

From line#1–4 are the import statements necessary to run this service. Line #12–14, we are making a default route/path for our API which would simply return this message- “Congratulations! Your Node Express API works.”

on Line 16, we are starting the express server on port 3000.

Now, lets create “tsconfig.json” in the project root directory(same level as package.json is at).

Add the following to “tsconfig.json”:

tsconfig.json

We are setting the source directory (which is ‘src’ in this case), the output directory(which is named ‘build’ in this case) and some compiler options like which ES standard we want the transpiler to follow.

Next, we will add few commands to scripts section in package.json to transpile our typescript code to javascript and to run the express server:

commands to build and run express server.

Here, ‘tsc’ command transpiles typescript to javascript. ‘clearBuild’ command deletes everything from build directory. ‘build’ command combines the ‘clearBuild’ and ‘tsc’ commands. Finally, the ‘startServer” command runs app.js which in turn start the express server on port 3000.

Now, open a command prompt in the project folder(where ‘package.json’ is there) and execute “npm run build”:

After it builds successfuly, you should see ‘build’ directory and you should see ‘app.js’ under it:

app.js

Now we are ready to run our first node Express service. Execute “npm start startServer” from the command prompt. You should see “ready on port 3000” after it runs successfully:

Now we are ready to invoke our default API. Let’s open a browser and type “http://localhost:3000/” and hit enter.

If you look at the console, you should see “request received” :

console log

The browser should show the message we had typed in ‘app.ts’:

successful API call

At this point, we have our node express service project setup and got it running.

After successful initial setup, we will now add AWS SDK to interact with one of the AWS services- AWS DynamoDB. I am assuming you are familiar with AWS DynamoDB and you have an AWS account. To start with, you would need AWS credentials configured at $HOME/.aws/credentials. This file contains ‘aws_access_key_id’ and ‘aws_secret_access_key’ corresponding to your AWS account and user.

aws credentials file

Next, create a DynamoDB table in your account named ‘users’ with 2 parameters- ‘userId’ and ‘name’. I have added one item with ‘userId’:’1' and ‘name’:’John’ as shown below:

We will add an API to retrieve this user from DynamoDB table and return to the browser.

Let’s add import statement for ‘aws-sdk’: “import * as AWS from ‘aws-sdk’;”

aws-sdk

Now set the region in which we have our ‘users’ in DynamoDB: “AWS.config.update({region:’us-east-1'});” . Here are we are updating the AWS config region to ‘us-east-1’.

aws config

Now it’s time to add the API call- ‘users’. Add the following code to ‘app.ts’:

let dynamodb = new AWS.DynamoDB();

app.get(‘/users’, (req, res) => {

console.log(“request received, fetching user”);

let user = {};

let dbParams: AWS.DynamoDB.GetItemInput = {

TableName : ‘users’,

Key: {

“userId” : {

S: ‘1’

}

}

};

// DynamoDB.GetItemInput

dynamodb.getItem(dbParams, function(error, data){

if(error){

console.log(‘No user found: ‘,error);

res.json(user);

}else{

if(data){

console.log(‘user is : ‘+data);

user = data;

res.json(data);

}

}

});

});

‘/users’ API

Let’s now build and start the server again. Open a web browser and type this path: “http://localhost:3000/users” and hit enter. At this point, you should see response showing the desired item from ‘users’ table from AWS DynamoDB:

‘/users’ API response

So now we have Node Express server with AWS SDK and we have successfully implemented an API to fetch data from AWS DynamoDB.

Next, we are going to deploy our API as an AWS Lamdba function. We will set up an AWS API Gateway which sits between the API consumer (a mobile app, a web app or simply a web browser for our demo). The consumer invokes our API call via API Gateway and the API Gateway in turn calls our Lambda function. In this way, API Gateway is simply a proxy hiding the implementation details from the API consumers.

You can read more about AWS API Gateway at : https://docs.aws.amazon.com/apigateway/latest/developerguide/welcome.html

We need a Javascript fucntion which would be invoked by AWS Lamdba. Let’s add a file -’lambda.js’ which would contain the Lambda handler:

We would have to make a change to app.ts. Instead of starting the express server in app.ts, we would just export the app. We would use the ‘app’ in ‘lambda.js’ to serve calls from lamdba.

We will use aws-serverless-express wrapping the ‘app’ and pass it to the lambda handler function as shown on line #25 below.

Now we will create a configuration file for our proxy API. I have named it ‘MyServerlesssDemoLambda-proxy-api.yaml’. This file contains information which AWS will use to create a proxy API.

(you can find this file in my git hub repository- ).

Next, we create a template file which refers the proxy API definition and tells AWS to create an API Gateway and as AWS Lambda function- ‘MyServerlesssDemoLambda-cloudformation-template.yaml’.

serverless-api-template.yaml- summary

The above image shows what resources we are going to create in AWS. We are creating- ApiGateway, the lambda function (MyServerlessDemoLambda) and the roles to execute the lambda fucntion.

The above image shows details for ApiGateway resource. the key detail here is on Line#9- ‘DefinitionUrl’. Here we are telling AWS to get the APIGateway definition from a file named ‘MyServerlesssDemoLambda-proxy-api.yaml’.

Now we will transpile our code and make it ready to be deployed.

Now we use AWS CLI and prepare package using AWS Cloudformation:

Once Cloudformation package compeletes, we will create all the resources we had mentioned in the Cloudformation template:

Once the stack is created successfully, we can see the API Gateway on AWS Console:

We can invoke the same API via AWS API Gateway:

As a final part, I am going to setup ‘DynamoDB Local’ which can be used just like AWS DynamoDB Service during development and unit testing. This could save money by not hitting AWS DynamoDB service where each read or write could count towards your monthly billing.

First download the DynamoDB Local from internet: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.html

Save it on your computer and unzip the contents. The contents would look like:

Open a command prompt in this folder and run “ java -jar .\DynamoDBLocal.jar -help”

This shows you the options you can provide while running DynamoDB locally:

I am going to specify the directory where I want to save my database file. I am also specifying that it is a shared Database.

Here I have pointed dbPath to a folder inside my Node-Express-Typescript project. The idea here is to check in the database file along with the code to code repository so that other team members can use it as well. As the team works on different APIs, they can collaborate and collectively add to the shared database.

At this point, DynamoDB Local is up and running. We can open a shell by “http://localhost:8000/shell” in the browser. This is an interactive shell where you can execute DynamoDB API calls. Though you can use the shell to create tables, add items to tables etc. although you can an npm plugin to manage the DynamoDB local. Run “npm install dynamodb-admin — only=dev” (More on DynamoDB-Admin at: https://www.npmjs.com/package/dynamodb-admin).

Once the plugin in installed, add a command in package.json under scripts section:”dynamoDbAdmin” : “node ./node_modules/dynamodb-admin/bin/dynamodb-admin.js”

We are now ready to run the DynamoDB Admin. Open a command prompt and run ‘dynamoDbAdmin’ script: “npm run dynamoDbAdmin”

At this point, we have DynamoDB local running at port 8000 and DynamoDB Admin running at port 8001. DynamoDB Admin is connected to DynamoDB Local at port 8000. Now open “http://localhost:8001” in a browser and see the DynamoDB Local:

This is much simpler user interface to create tables and add test data.

I will create a table ‘users’ with Key as ‘userId’. I will add another attribute with name ‘name’. This matches with the schema I create earlier in AWS DynamoDB service.

Once I create the table, it shows up under tables:

Now I am going to add few items to this table.

So, now I have some data to test my API call. Before I run the code, I will make a small change to the code to use local endpoint for DynamoDB:

With this change, our code will point to the DynamoDB Local instead on AWS DynamoDB Servcie. Now just rebuild and run the project:

Open browser and enter “http://localhost:3000/user”. This is the same API call which got the results from AWS DynamoDB. This time it is going to retrieve result from local DynamoDB:

This is the same item I had added to DynamoDB local earlier.

Now I close DynamoDB Local. It saves the table I created and the items I added to a file- ‘shared-local-instance.db’ under the dbPath I had mentioned at startup.

If I start DynamoDB again with same options as last time, It will take the load the database state from ‘shared-local-instance.db’ file and I am good to go further.

Hope this could serve as starter for those planning to use Node.js, Express with TypeScript as AWS Lambda function and to integrate with AWS DynamoDB.

GitHub repository with sample code: https://github.com/sk-saurabh/serverlessNodeExpressServices

That’s it for now. Happy coding!