Skip to content
By Victor Hazbun

Serverless Node apps on AWS Lambda

What is Serverless?

Serverless can be summed up as Functions as a service (FaaS). It consists of ephemeral containers that auto-scale and have a pay-per-execution pricing. It runs your functions in the cloud without the need of a server, PERIOD.

Pros

  • Low-Price, the cost of these functions being executed is much lower than having your own custom host.
  • Auto-scale, as the function receives more and more requests, AWS Lambda will do it automatically for you.
  • Zero maintainability, you don't need to personally maintain the server hosting your functions.

Cons

  • Hot-cold fashioned, the functions are turned off after a period of inactivity. They will be restarted only after a request has been made, which will result in a delay on the response.
  • Environment blocked, you can't install additional packages or software, so if your function depends on a third party package, you can forget about using AWS Lambda.
  • Different environments, the changes you have made in one instance are not guaranteed to be persisted in the next instance. All will be wiped out (randomly).

How to battle against Cons

These cons do all have work-arounds however, as I will detail below.

Hot-cold fashioned

Use WarmUP to keep your lambdas warm.

Environment blocked

Tell your function to consume an API that hosts the software you depend on.

Different environments

Explicitly store the files you need to persist using AWS S3.

Setup

Visit AWS AIM console, create a new User, next give them Programmatic access and AdministratorAccess. Once confirmed, store the Access key ID and the Secret access key.

Finally, install the AWS CLI, and set up the access key Access key ID and the Secret access key.

brew install awscli

aws configure

Serverless Framework

Install the serverless framework.

npm install -g serverless

Manual setup

Let's setup the serverless framework in our app manually. And expose two API endpoints, create user and get one user.

serverless create --template aws-nodejs --path api

cd api

mkdir todos

// api/package.json
{
  "name": "api-todos",
  "version": "1.0.0",
  "description": "Create and Get one Todo",
  "author": "",
  "license": "MIT",
  "dependencies": {
    "uuid": "^2.0.3"
  }
}

Install our dependencies npm install (AWS Lambda will install the dependencies as well).

# api/serverless.yml
service: api

provider:
  name: aws
  runtime: nodejs8.10
  environment:
    DYNAMODB_TABLE: ${self:service}-${opt:stage, self:provider.stage}
  iamRoleStatements:
    - Effect: Allow
      Action:
        - dynamodb:GetItem
        - dynamodb:PutItem
      Resource: "arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/${self:provider.environment.DYNAMODB_TABLE}"

functions:
  create:
    handler: todos/create.create
    events:
      - http:
          path: todos
          method: post
          cors: true
  get:
    handler: todos/get.get
    events:
      - http:
          path: todos/{id}
          method: get
          cors: true

resources:
  Resources:
    TodosDynamoDbTable:
      Type: 'AWS::DynamoDB::Table'
      DeletionPolicy: Retain
      Properties:
        AttributeDefinitions:
          -
            AttributeName: id
            AttributeType: S
        KeySchema:
          -
            AttributeName: id
            KeyType: Hash
        ProvisionedThroughput: 
          ReadCapacityUnits: 1
          WriteCapacityUnits: 1
        TableName: ${self:provider.environment.DYNAMODB_TABLE}

Next, create each function file.

// api/todos/create.js
'use strict';

const AWS = require("aws-sdk");
const uuid = require ("uuid/v4");
const client = new AWS.DynamoDB.documentClient();

module.exports.create = async (event) => {
  const data =JSON.parse(event.body);
  const params = {
    TableName: "todos"'
    Item: {
      id: uuid(),
      text: data.text,
      checked: false
    }
  };

  await client.put(params).promise();
  return{
    statusCode: 200,
    body: JSON.stringify(data)
  };
};
// api/todos/get.js

'use strict';
const AWS = require("aws-sdk");

const dynamoDb = new AWS.DynamoDB.DocumentClient();

module.exports.get = async (event) => {
  const params = {
    TableName: "todos",
    Key: {
      id: event.pathParameters.id
    }
  };

  const result = await dynamoDb.get(params).promise();
  if (result.Item) {
    return {
      statusCode:200,
      body: JSON.stringify(result.Item)
    };
  } else {
    return {
      statusCode: 404,
      body: JSON.stringify({ message: "Couldn't find the todo item." })
    };
  }
}
  • event is an object containing the request data.
  • context is an object containing the AWS info.
  • callback is a function that will be invoked with an error response as first argument or a valid response as second argument.

Deploy

Deploying is one of the coolest parts. :-)

sls deploy

Once deployed you can test the function.

Create a Todo

curl -X POST https://XXXXXXX.execute-api.us-east-1.amazonaws.com/dev/todos --data '{ "text": "Learn Serverless" }' Output:

{"text":"Learn Serverless", "id":"ee6490d0-aa11e6-9ede-afdfa051af86", "createdAt":1479138570824, "checked":false, "updatedAt":1479138570824}%

Get one Todo

# Replace the <id> part with a real id from your todos table curl https://XXXXXXX.execute-api.us-east-1.amazonaws.com/dev/todos/<id>

Output:

{"text":"Learn Serverless", "id":"ee6490d0-aa11e6-9ede-afdfa051af86", "createdAt":1479138570824, "checked":false, "updatedAt":1479138570824}%

More about deployment

You can also deploy JUST the function (This is pretty fast).

serverless deploy function -f create

DynamoDB

When creating a table, you need to specify how much provisioned throughput capacity you want to reserve for reads and writes. DynamoDB will reserve the necessary resources to meet your throughput needs while ensuring consistent, low-latency performance. You can change the provisioned throughput by increasing or decreasing capacity as needed.

Concurrent executions

By default, AWS Lambda limits the total concurrent executions across all functions within a given region to 100. The default is a safety limit that protects you from costs due to potential runaway or recursive functions during initial development and testing. To increase this limit above the default, follow the steps in To request a limit increase for concurrent executions.

Handling lots of traffic

If you expect to have a lot of traffic it's recommended to switch to the auto scaling option for DynamoDB.

Real world use cases

AWS Lambda or any other Lambda could be used for multiple purposes, like: - Data processing - Backends - IoT - Bots

Learn more about use cases

Final thoughts

No more servers? Well, certainly no. This will not replace the need for servers (at least not now). However, it's a great tool to develop micro-services and many other things.

Latest Articles by Our Team

Our expert team of designers and developers love what the do and enjoy sharing their knowledge with the world.

We Hire Only the Best

reinteractive is Australia’s largest dedicated Ruby on Rails development company. We don’t cut corners and we know what we are doing.

We are an organisation made up of amazing individuals and we take pride in our team. We are 100% remote work enabling us to choose the best talent no matter which part of the country they live in. reinteractive is dedicated to making it a great place for any developer to work.

Free Community Workshops

We created the Ruby on Rails InstallFest and Ruby on Rails Development Hub to help introduce new people to software development and to help existing developers hone their skills. These workshops provide invaluable mentorship to train developers, addressing key skills shortages in the industry. Software development is a great career choice for all ages and these events help you get started and skilled up.

  • Webinars

    Webinars

    Webinars are our online portal for tips, tricks and lessons learned in everything we do. Make the most of this free resource to help you become a better developer.

    Learn more about webinars

  • Installfest

    Installfest

    The Ruby on Rails Installfest includes a full setup of your development environment and step-by-step instructions on how to build your first app hosted on Heroku. Over 1,800 attendees to date and counting.

    Learn more about Installfest

  • Development Hub

    Development Hub

    The Ruby on Rails Development Hub is a monthly event where you will get the chance to spend time with our team and others in the community to improve and hone your Ruby on Rails skills.

    Learn more about Development Hub

Get the “reinteractive Review” Monthly Email