Blog

Creating Your First Serverless App with AWS Lambda and the Serverless Framework

Ilya Drabenia

serverless-architectures

Serverless architectures are one of the newest trends in computing that brings reduced infrastructure and development costs to the table. According to this approach, an application is split into multiple functions with each of them deployed separately.

Here, we demonstrate how to create a serverless application and deploy it to AWS Lambda, as well as explain some of the architecture basics.

 

Serverless architectures

In serverless architectures, all routines that process events are defined individually. This allows assigning computation resources to the routine only when it is executed and minimizes the time when the resources are used.

serverless-architectures

Blog application deployed according to the serverless model

Currently, among the major vendors that provide supporting services for serverless architectures are AWS Lambda, Google Cloud Functions, OpenWhisk (available in IBM Bluemix), and Azure Functions.

For instance, OpenWhisk creates a Docker image for each function. When an event requires processing, OpenWhisk runs these images in a container and processes the event. Then, the service suspends the container and puts it to cache. If the functions are called frequently, the existing container is reused from the cache. Otherwise, OpenWhisk will create a new container for each request.

ibm-openwhisk-event-processing-algorithm

Event processing algorithm for OpenWhisk

However, the serverless model is not ideal for development. The separate definition and deployment of functions is not very useful when implementing applications. For this reason, there are a number of frameworks—such as Serverless, Apex, and Lambada—that allow you to simplify the development and implement functionality without a paradigm shift.

 

The Serverless framework

Among the most known frameworks that make the implementation of serverless architectures easier is Serverless. It provides a set of command line tools for creating, deploying, and invoking serverless applications. At the current time, Serverless supports only AWS Lambda; it is also planned to add OpenWhisk, Azure Functions, and Google Cloud Functions on the list in future releases.

With the framework, you can create an application in a usual way, define all functions that will be used for event processing, and deploy this application to the cloud.

To get started, we need to create a project:

Ilyas-MacBook-Pro:prototypes idrabenia$ mkdir serverless-hello
Ilyas-MacBook-Pro:prototypes idrabenia$ cd ./serverless-hello/
Ilyas-MacBook-Pro:serverless-hello idrabenia$ serverless create --name test --template aws-nodejs
Serverless: Creating new Serverless service...
 _______                             __
|   _   .-----.----.--.--.-----.----|  .-----.-----.-----.
|   |___|  -__|   _|  |  |  -__|   _|  |  -__|__ --|__ --|
|____   |_____|__|  \___/|_____|__| |__|_____|_____|_____|
|   |   |             The Serverless Application Framework
|       |                           serverless.com, v1.0.0-rc.1
 -------'

Serverless: Successfully created service with template: "aws-nodejs"
Serverless: NOTE: Please update the "service" property in serverless.yml with your service name
Ilyas-MacBook-Pro:serverless-hello idrabenia$ ls
event.json    handler.js     serverless.yml

After this sample project is created, you can see three files. Below is the serverless.yaml configuration file:

service: aws-nodejs # NOTE: update this with your service name

provider:
  name: aws
  runtime: nodejs4.3

functions:
  hello:
    handler: handler.hello

The file contains the configuration of the function that will be deployed to the cloud.

The handler.js file includes the definition of this function:

'use strict';

// Your first function handler
module.exports.hello = (event, context, cb) => cb(null,
  { message: 'Go Serverless v1.0! Your function executed successfully!', event }
);

// You can add more handlers here and reference them in serverless.yml

Thus, you can just specify the functions of your application in serverless.yaml and implement it as a traditional web application.

The third file—event.json—contains a sample event for the default handler.

 

Creating your first serverless application

To implement serverless architecture, we decided to create a simple REST API for the CRUD operations of the application user entity. In this scenario, we used the DynamoDB NoSQL database provided by AWS.

aws-lambda-serverless-architectures

Project structure

For implementing the entity model and persistence, we used the vogels library and Joi validator.

The model/user.js file:

'use strict';

let vogels = require('vogels');
let Joi = require('joi');
vogels.AWS.config.update({region: 'us-east-1'});


let User = vogels.define('User', {
 hashKey: 'email',

 // add the timestamp attributes (updatedAt, createdAt)
 timestamps: true,

 schema: {
   email: Joi.string().email(),
   firstName: Joi.string(),
   lastName: Joi.string(),
   age: Joi.number(),
   roles: vogels.types.stringSet(),
   settings: {
     nickname: Joi.string(),
     acceptedTerms: Joi.boolean().default(false)
   }
 }
});

module.exports = User;

Also, there is a controller that enables all required CRUD operations and exposes them through a REST API. Here is the code of the controller/user.js file:

'use strict';

let User = require('./../model/user');
let vogels = require('vogels');


function UserController () {
 let self = this;

 self.create = function (event, context, cb) {
   vogels.createTables(() => User.create(user, cb));
 };

 self.list = function (event, context, callback) {
   User.scan().limit(20).exec(callback);
 };

 self.update = function (event, context, callback) {
   new User(event.body).save(callback);
 };

 self.delete = function (event, context, callback) {
   User.destroy(event.path.id, (err) => callback(err, {}));
 };
}

module.exports = new UserController();

The configuration for the API is below:

service: aws-nodejs 
provider:
 name: aws
 runtime: nodejs4.3
 iamRoleStatements:
   - Effect: "Allow"
     Action:
       - "*"
     Resource: # next role requires to allow AWS Lambda routines access to DynamoDB
       - "arn:aws:dynamodb:us-east-1:[ACCOUNT_ID]:table/*"

functions:
 userCreate:
   handler: lib/controller/user.create
   events:
     - http: POST user

 userList:
   handler: lib/controller/user.list
   events:
     - http: GET user

 userUpdate:
   handler: lib/controller/user.update
   events:
     - http: POST user/{id}

 userDelete:
   handler: lib/controller/user.delete
   events:
     - http: DELETE user/{id}

Then, we can deploy the application to AWS Lambda:

ilyas-mbp:serverless-probe idrabenia$ serverless deploy
Serverless: Packaging service...
Serverless: Removing old service versions...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading service .zip file to S3...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
........................................................
Serverless: Stack update finished...

Service Information
service: aws-nodejs
stage: dev
region: us-east-1
endpoints:
  POST - https://wtiqkzaow2c.execute-api.us-east-1.amazonaws.com/dev/user
  GET - https://wtiqkzaow2c.execute-api.us-east-1.amazonaws.com/dev/user
  POST - https://wtiqkzaow2c.execute-api.us-east-1.amazonaws.com/dev/user/{id}
  DELETE - https://wtiqkzaow2c.execute-api.us-east-1.amazonaws.com/dev/user/{id}

It is also possible to test the API using Postman:

creating-serverless-apps

Receiving the list of users through the developed REST API

 

Conclusions

The serverless model promises new opportunities for low-cost computing. With libraries like the Serverless framework available, it is quite simple to use this architecture to implement fully functioning applications. Overall, the serverless model seems to be a good fit for some small and medium-sized web applications, including e-shops, corporate websites, forums, and blogs. Now available exclusively for AWS Lambda, hopefully the Serverless framework would feature support for OpenWhisk as well.

 

Related reading

 

About the author

Ilya Drabenia is a Technical Lead at Altoros. He has broad experience in building software architectures, including design and development of complex solutions. Ilya is passionate about microservices, domain-driven design, as well as scalable and parallel algorithms. He also holds an MS degree in Computer Science. See his profile on GitHub.


For the next parts of this series, subscribe to our blog or follow @altoros.

Get new posts right in your inbox!

No Comments

Benchmarks and Research

Subscribe to new posts

Get new posts right in your inbox!