How to Get Started With Serverless, Express and AWS Lambda

What are we building?

In this guide, we will learn how to set up a simple Node.js/Express API powered by AWS Lambda and what the pros and cons are for such a setup. I hope that it can help developers get the fastest setup as possible with Express/AWS Lambda and make their journey better, less frustrating and enjoyable using serverless.

Let’s jump right in!

The repository for this guide can be found at GitHub.

Prerequisites

Make sure Node.js is installed and the version is Node.js 8 or above. Download and install Node.js, or follow this guide.

Install Serverless Framework

Next, install the Serverless Framework via npm which was already installed when you installed Node.js.

npm install -g serverless

Setting up an AWS Account With Serverless Framework

If you haven’t signed up to AWS yet, you can sign up at AWS Free Tier Account.

Serverless Framework is the most widely-adopted toolkit for building serverless applications. The Serverless Framework is an open-source CLI for building and deploying serverless applications.

It currently supports major serverless providers such as: AWS, Google Cloud, Azure, Oracle Fn, and more.

After installation, configure serverless with the AWS account key and secret:

serverless config credentials --provider aws —-key xxxxxxxxxxxxxx --secret xxxxxxxxxxxxxx

Where the key and secret are the account key and account secret provided by AWS.

Install Dependencies

Let’s install express, CORS, and serverless-http. You can add any dependencies your app requires. CORS is a mechanism that allows restricted resources on a web page to be requested from another domain outside the domain from which the first resource was served.

The CORS npm package is a Node.js package for providing a Connect/Express middleware that can be used to enable CORS with various options.

We’ll install serverless-http npm package. This is required to convert AWS Lambda event to an Express request/response object. serverless-http cleans up the event, sanitises headers, checks if the header is base64 encoded and dispatches an async callback. serverless-http currently supports Express, Koa, connect, Hapi.js and more.

npm install — save express cors serverless-http

From serverless-http README on GitHub:

Your code is running in a serverless environment. You cannot rely on your server being ‘up’ in the sense that you can/should not use in-memory sessions, web sockets, etc. You are also subject to provider-specific restrictions on request/response size, duration, etc.

Next, we will setup our serverless.yml config.

Serverless.yml

This is the configuration file for the AWS Lambda function we need. Notice that we use two events for the function:

  • Root route: /
  • Proxy {proxy+}: /* (to make Express handle the rest of the requests)

You can read more about serverless.yml in the documentation.

service: expressAPI-epsagon
provider:
name: aws
runtime: nodejs8.10
stage: dev
region: eu-central-1
functions:
server:
handler: index.server
events:
- http: ANY /
- http: ‘ANY {proxy+}’

Index.js

This is our AWS Lambda entry point. Notice that the server can be any supported web server from `serverless-http`, making the function pluggable to Express, koa, Connect, hapi.js (experimental) and more. Serverless wraps our app and returns a promise. This way we can use async-await instead of the callback-based Lambda functions.

const serverless = require(‘serverless-http’);
const server = require(‘./app’);
const handler = serverless(server);
module.exports.server = async (event, context) => {
return await handler(event, context);
};

Express Server (app.js)

This is a simple express API example.

const express = require(‘express’);
const cors = require(‘cors’);
const apiRouter = require(‘./api’);
const errorHandler = require(‘./helpers/errorHandler’);
const server = express();
server.use(cors());
server.use(express.urlencoded({ extended: true, strict: false }));
server.use(express.json());
server.get(‘/’, (req, res) => {
res.json({
message: ‘Express API Powered by AWS Lambda!’
});
});
server.use(‘/v1/api’, apiRouter);
server.use(errorHandler.notFound);
server.use(errorHandler.internalServerError);
module.exports = server;

Deployment

Time to make our server come to life! Hit this command, sit back a minute, and let Serverless magically deploy our function to AWS.

serverless deploy
Deploying using Serverless Framework

It’s live. See endpoints for the full link (AWS will generate different URLs for different functions).

Notice the region and stage of the function — in our case, it’s `eu-central-1` and in dev mode. It’s configurable in serverless.yml.

Root route: `\`

API route: `\v1\api`:

Troubleshoot

In case you run into any errors, you need to display logs:

serverless logs -f server -t

-f is the function name, -t is the function tail (latest request log). In case of an error, it will display the error message and stack. This request is successful:

AWS Lambda log tailing

Notice the RequestId, HTTP method and path and the Lambda invocation details: Init duration, Duration, Billed Duration, Memory Size, and Max Memory.

Clean

Serverless has helper command to remove the function and all related resources (S3 bucket objects, CloudFormation Stack) completely. After you’re done playing, don’t forget to remove the resources to keep your AWS account clean.

serverless remove

Pros/Cons

Express API powered by AWS doesn’t require any server setup. It is scalable as you need it to be and speeds up the development and deployment process. This way, you can spend your time developing the business instead of dealing with servers and clusters.

This will provide your stack an ability to connect to other services AWS has to offer, e.g. integration with AWS SNS, DynamoDb/RDS, S3 and much more.

But it doesn’t come without a cost.

Lambda functions have some limitations that you should be aware of:

  • Functions are stateless
  • Cold starts
  • Maximum execution duration per request
  • Function timeout (15min)
  • Invocation payload size: request and response (6MB synchronous, 256Kb asynchronous), and more

Summary

In this guide, we’ve created a serverless Express application powered by AWS Lambda. We learned about the frameworks we need to get up and running as fast as possible. This example is simple but extremely flexible for getting started.

We will have a follow up on this guide, and add client-side application integration, with React and Angular guides stored on S3 with CloudFront.


Yotam Elkaslasy is a senior JavaScript developer at Epsagon, an observability platform for serverless applications. Currently focused on using distributed tracing and AI technologies to tackle the unique observability challenges in serverless environments.