Using AWS Lambda With Nodejs

Rahul Tripathi
4 min readSep 14, 2020

--

the lambda

Welcome everyone !, This short article will explain how you can structure and write your lambda code to efficiently handle API requests in Nodejs . We’ve been running lambda in production for quite some time using the same approach and it has worked very well for us so let’s get started …

The Directory Setup

directory tree (printed using tree)

The project setup is pretty simple and is based upon the sample web project that AWS ships with the SAM tool .

The root folder consists of the configuration files(samconfig.toml , template.yml) along with the tests folder and jest config .

All the code that needs to be shipped resides in the package folder which has node_modules , package.json , index.js (handler file) , the src and the config directory

The src directory uses the good ol’ ( routes → controllers ← → models) architecture . The config directory is used to initialize DB Connections and store configuration . The alternate way to store configs is in the ENV variable but i prefer using the JSON file while working with multiple configuration keys .

The ENV variables can be set in the template.yml file or from the lambda dashboard , these can be used to set DB connection strings and passwords .

A Deep Dive Into The Code

PS: Ignore my drawing skills

The above Illustration explains how api-gateway triggers the Lambda function . The api gateway generates an event for every Api trigger which can be used by our lambda function , here’s a sample event object

{  
"body": "",
"resource": "/{proxy+}",
"path": "/api/sample/hello",
"httpMethod": "GET",
"isBase64Encoded": true,
"queryStringParameters": {
"foo": "bar"
},
.......
"headers":{
....
}
.......
}

The event object contains a lot of information , but lets take a look at the important values ,

  • path — contains the requested path
  • headers — contains all the headers sent in the request along with the gateway headers
  • httpMethod — Type of Request (GET / POST / PUT etc)
  • queryStringParameters — Query params send in the request

The above given object translates to

GET http://api-gateway/prod/api/sample/hello?foo=bar

The Handler

The handler function is the entry point of the lambda function , it is invoked whenever the lambda function is called .

This is a sample handler file , note that we initialize the Database connection outside the handler , this is because we want to persist a single connection for a single lambda instance or else we’ll end up creating a lot of connections and will also face ERRCONNTIMEOUT errors (timeout errors) .

Here we are directly returning a promise into the runtime which makes the handler asynchronous

Request multiplexing

Request multiplexing can be done in many ways such as

  • Wrapping a server in place of lambda handler which can handle and route requests (eg : https://github.com/awslabs/aws-serverless-express) , This library is basically a wrapper written around express which binds an express app to your lambda handler . This approach is good but can cost you a good amount of cold-startup time .
  • Multiplexing based on the event object : since we have the path in the event object , we can directly call the corresponding resolver by evaluating the path . This reduces the cold-start time but may lack features of a http-server

This is a sample router file from our code , you’ll notice we are not using express (req,res,next)=>{} handler instead we’re using a library which does the routing

This library takes the event object as the input and returns the corresponding promise which can be directly returned to the runtime . This approach removes the performance overhead caused by spinning up a server .

The Controllers

The controllers remain the same as in any other http server ,here instead of taking the req,res objects they take event as parameter and return a promise , here is a sample controller to get user details from DB

The function formatRes builds a http response object from the given data

/* formatRes(data,statusCode,headers)=>httpResponseObject */const formatRes = (data, code, headers) => {
return {
headers: {
"Access-Control-Allow-Headers": "application/json",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "OPTIONS,POST,GET",
"Content-Type": "application/json"
},
body: (data != null || code ) ? JSON.stringify({
result: {
data: data
},
statusCode: code ? code : 500
}) : JSON.stringify({
data: "Internal Server Error",
statusCode: 500
}),
statusCode: code ? code : 500
}
}

TL;DR

I’ve build a sample project and can be found at the following github repository , so check it out if you’re a SHOW ME THE CODE guy :)

Feel free to drop a question or a feedback below :). Also check out this article which explains how you can setup your lambda function before starting with the code

--

--