How can we setup Lambda using Serverless Framework and Best way to write AWS Lambda in Nodejs v12.x

Soni Pandey
5 min readFeb 19, 2020

Nodejs v12.x is LTS version of Node.js until October 2020 and after that, it’ll move into Maintenance until end of April 2022.

AWS Lambda has also provided the support of Nodejs v12.x. There are multiple ways to work with AWS Lambda -

  1. Upload zip of source code.
  2. Use Cloudformation Template to work with Lambda Function.
  3. Follow Serverless Framework steps to work with Lambda.

In this article, we’ll use Serverless Framework to work with AWS Lambda and will learn about -

1. How can we kick off the project using serverless framework?
2. How to keep config file separate?
3. How to declare environment variables and use that in code?
4. Write Lambda function in Nodejs v12.x.
5. How can we make response CORS part common?

Prerequisites -

Follow these steps if your machine is not having any of these -

i) Install Node.js® and npm.

ii) Installing the Serverless Framework

Open up a terminal and type npm install -g serverless to install Serverless.

npm install -g serverless 

You can check out this also for installation guideline steps.

iii) Sign up for an AWS account.

iv) Configure AWS CLI.

Follow these steps for last two steps.

How can we kick off the project using serverless framework?

Let’s take an example for moving forward to work with Serverless Framework. We are going to perform CRUD operation for user and creating service for the same using Serverless.

We can keep our project structure in this format -

In the services folder, we can have multiple services eg. user-service, product-service and many more. configuration file (config.yml) will be on root level in services folder as we can use for all services. Each service will have serverless.yml, package.json and specific file for business-logic.

How to keep config file separate?

Our config file will look like this, this can be customized as per our requirement -

#config.yml
---
stage: dev
region: us-west-2
profile: default
tables:
users:
name: users
readCapacity: 1
writeCapacity: 1

We are keeping configuration file separately and it could have all the details which are going to use multiple places and should be in config file.

Let’s move to specific user-service and have a look at the serverless.yml file -

#serverless.yml
service: user-service
provider:
name: aws
profile: ${self:custom.config.profile}
runtime: nodejs12.x
region: ${self:custom.config.region}
stage: ${self:custom.config.stage}
memorySize: 128
timeout: 30
versionFunctions: false
environment:
STAGE: ${self:custom.config.stage}
TABLE_USER: ${self:custom.config.tables.users.name}-${self:custom.config.stage}
functions:
user-create:
handler: functions/create.main
events:
- http:
path: /users
method: post
cors: true

user-get:
handler: functions/get.main
events:
- http:
path: /users
method: get
cors: true

user-get-by-id:
handler: functions/getById.main
events:
- http:
path: /users/{id}
method: get
cors: true
custom:
config: ${file(./config.yml)}

Give your own service name, I have chosen user-service.
Provider properties details:

  • name — We are using aws.
  • profile — set profile from your system.
  • runtime — AWS highest version supported till now nodejs12.x
  • region — In which region you want to deploy your functions. Please check region list.
  • stage — it’s upto you, I prefer dev, qc or prod.
  • memorySize — It is optional, in MB, default is 1024. Minimum = 128 MB / Maximum = 3008 MB (with 64 MB increments). If the maximum memory use is exceeded, function invocation will be terminated. I keep it 128 MB.
  • timeout — It is also optional, in seconds, default is 6. Maximum execution duration per request 300 seconds, I keep it 20 seconds max.
  • versionFunctions — By default, the framework creates function versions for every deploy. This behavior is optional, and can be turned off in cases where you don’t invoke past versions by their qualifier. I keep it as a false.
  • environment — This is used for defining all the variables which we wanted to use in the environment and can be used as process.env.variableName.

You can add as many functions as you want within this property. The code will look like this.

Functions properties details:

  • handler — The handler property points to the file and module containing the code you want to run in your function.
  • events — All events in the service are anything in AWS that can trigger an AWS Lambda function, like an S3 bucket upload, an SNS topic, and HTTP endpoints created via API Gateway. Here, we are using HTTP endpoints created via API Gateway. The events property is an array, because it’s possible for functions to be triggered by multiple events, as shown. You can set multiple Events per Function, as long as that is supported by AWS.

To deploy or update your Functions (user-create, user-get etc.), Events and Infrastructure, run

serverless deploy -f user-create

or deploy all functions in one shot -

serverless deploy

NOTE: If there is any dependency module you have used then make sure that you have run the below command before serverless deploy-

yarn install or npm install

How to declare environment variables and use that in code?

In serverless.yml file, we declare all the environment variables -

environment:
STAGE: ${self:custom.config.stage}
.
.
.

Write Lambda function in Nodejs v12.x.

Let’s walkthrough of one function’s logic -

# create.js
const AWS = require("aws-sdk");
const db = new AWS.DynamoDB.DocumentClient();
const {createErrorResponse, createSuccessResponse} = require('./common');
exports.main = async (event) => {
try {
const {data} = JSON.parse(event.body);
const params = {
TableName: process.env.TABLE_USER,
Item: data
};
const result = await db.put(params).promise();
return createSuccessResponse(result);
} catch (ex) {
return createErrorResponse(ex);
}
};
  1. We’re not using callback for any operation to db as well and used promise in place of that.

Promises are the ideal choice for handling asynchronous operations in the simplest manner. They can handle multiple asynchronous operations easily and provide better error handling than callbacks and events.

2. The similar way of achieving promise we have used async-await mechanism also.

Async functions enable us to write promise based code as if it were synchronous, but without blocking the execution thread. It operates asynchronously via the event-loop. Async functions will always return a value. Using async simply implies that a promise will be returned, and if a promise is not returned, JavaScript automatically wraps it in a resolved promise with its value. #copiedfrom Ashay Mandwarya 🖋️💻🍕

In the similar way, we have written other APIs business logic.

How can we make response CORS part common?

const commonResponseHeaders = {
"Access-Control-Allow-Origin": '*',
"Content-Type": "application/json "
};
/**
* @fileOverview Create an error response
* @param {Object} ex Exception object
* @param {String} ex.message Exception message
* @param {Number} [ex.statusCode] Exception message
* */
const createErrorResponse = (ex) => ({
statusCode: 500 || ex.statusCode,
message: "Internal Server Error" || ex.message,
headers: commonResponseHeaders
});
/**
* @fileOverview Create a successful response
* @param {String} body Stringified body object
* @param {Number} [statusCode] Success code
* */
const createSuccessResponse = (body, statusCode) => {
const bodyString = typeof body === 'object' ? JSON.stringify(body) : body;
return {
statusCode: 200 || statusCode,
body: bodyString,
headers: commonResponseHeaders
};
};
module.exports = {
createErrorResponse,
createSuccessResponse
};

Use createErrorResponse and createSuccessResponse all over the place where we are returning response data from lambda. This way we don’t need to write these specific lines all over the place and we have created generic functions which need to be invoked with the result data or error data.

Here is the source code. You can reach out to me for any doubt and suggestions.

Conclusion: Hope this article helps you to start your first project using serverless framework.

--

--

Soni Pandey

I am a Node.js Developer and eager to learn new technology. I blog, tweet & read whenever I can.