Developing AWS locally with Serverless offline plugins

No Comments

You are using the Serverless framework on AWS? Did you know that you can develop on your local machine as well with little effort? For this purpose, a variety of Serverless offline plugins are available which make it possible to use services like Lambda, DynamoDB or S3 locally. In this article, I will show you how to get started easily.

I will provide an example reduced to the bare necessities, and will only go into detail on the relevant parts of the offline plugins. I will get an AWS stack up and running locally, based on Node.js, API Gateway, lambdas, and DynamoDB.

Why offline plugins?

There are many reasons for using cloud-based services. Our blog contains a lot of great examples, maybe you want to have a look at these:

For developers, new obstacles are emerging that have been less critical in classical approaches. When the development environment is moved completely to a cloud provider, it usually takes more time and effort until a code change finally becomes visible in the product.

If you already work with the Serverless framework, you can benefit from the variety of available offline plugins to get your cloud project up and running on your local machine. The idea behind it is simple: the code you execute locally is also executed in the cloud.

Prerequisites

You should at least know the basics of the Serverless framework and also have it installed. You can check that easily by executing

$ serverless --version

in your shell and see if it responds with a valid version.

Furthermore, you should have Node.js installed and also understand the basics of this language.

Preparations

If you want to reproduce the following example, please clone it first from this repository. Additionally, we need some plugins. These statements:

$ npm install aws-sdk
$ npm install express
$ npm install serverless-http
$ npm install serverless-dynamodb-local
$ npm install serverless-offline
$ sls dynamodb install

will install all required plugins. serverless-dynamodb-local and serverless-offline are the candidates which enable us to develop locally.

Configuring plugins

As soon as all plugins are installed, they need to be included in the serverless project. This is done in the plugins-block.

plugins:
  - serverless-dynamodb-local
  - serverless-offline  # should be last in list

of the serverless.yml-file. This will make the plugins available for our project. Some minor configuration is required which we will add to the custom-section:

tableNames:
  persons: 'cc-persons'
    
dynamodb:
  start:
    migrate: true
  stages:
    - dev

tableNames defines the name of the DynamoDB table, so that we can reuse it in other places. migrate ensures that the required DynamoDB tables are created automatically on start up.

In projects where no local plugins are used, the AWS SDK automatically takes care of the AWS configuration. But for local plugins, that behavior is restricted: We need to tell the SDK the DynamoDB endpoint later. That’s why we configure it via

custom:
  endpoints:
    dynamodb-url: 'http://localhost:8000'

and publish the required values via

provider:
  environment:
    CONFIG_PERSONS_TABLE: ${self:custom.tableNames.persons}
    CONFIG_DYNAMODB_ENDPOINT: ${self:custom.endpoints.dynamodb-url}

as environment variables for later use. Finally, we need to create a DynamoDB table. We create a resource for it, described in a separate file resources/persons-table.yml, and embed it via

resources:
  - ${file(resources/persons-table.yml)}

into the resources-block of the serverless.yml-file.

Calling DynamoDB from the Node.js lambda

The Serverless framework will take care of creating tables. However, the access to the tables is implemented by ourselves in the Node.js lambdas. The project already contains two simple services which are defined in the serverless.yml files functions block:

  • GET on /persons
  • POST on /persons

The implementation is placed in handler/persons.js. It makes use of the Express framework, further details are not relevant for us at this point.

All calls on the DynamoDB that are invoked in our lambdas are encapsulated by the AWS SDK. However, the SDK does not know about our local DynamoDB yet and would connect us with the AWS cloud and redirect all queries to the cloud. Thus, we need to tell the AWS SDK which DynamoDB endpoint it should use while we are in offline mode.

To find out whether we are in offline mode, the serverless offline plugin provides an environment variable which we can check: IS_OFFLINE. We can use this variable to build a switch, overriding the endpoint in local mode.

const CONFIG_PERSONS_TABLE = process.env.CONFIG_PERSONS_TABLE;
const CONFIG_DYNAMODB_ENDPOINT = process.env.CONFIG_DYNAMODB_ENDPOINT;
const IS_OFFLINE = process.env.IS_OFFLINE;
 
let dynamoDb;
if (IS_OFFLINE === 'true') {
  dynamoDb = new AWS.DynamoDB.DocumentClient({
    region: 'localhost',
    endpoint: CONFIG_DYNAMODB_ENDPOINT,
  });
} else {
  dynamoDb = new AWS.DynamoDB.DocumentClient();
}

With this mechanism, the endpoint used in local mode is different than in normal (“cloud”) mode, namely the one we defined in the serverless.yml file as environment variable CONFIG_DYNAMODB_ENDPOINT.

Function testing

All other sources in this project look exactly the same as they would without using offline plugins, and therefore are not relevant for this article. We already made all required adjustments. Let’s now start testing if everything works as expected. With the statement

$ serverless offline start

the whole project will be started locally. Whether or not everything works correctly can be seen in the log output, for example

Dynamodb Local Started, Visit: http://localhost:8000/shell
Serverless: DynamoDB - created table cc-persons
Serverless: Starting Offline: dev/eu-central-1.
Serverless: Offline [HTTP] listening on http://localhost:3000

We can see that a local DynamoDB was started, and that the table cc-persons was created. Let’s now find out whether our services work correctly by executing the following statements:

$ curl -XPOST localhost:3000/persons
$ curl localhost:3000/persons

consecutively. This should create a new person and then return it back.

More opportunities

There are much more serverless offline plugins for the Serverless framework. For example, I tried serverless-offline-ssm and serverless-s3-local successfully. Using serverless offline plugins enables a developer to run an entire AWS stack locally and in an isolated manner, without always having the cloud infrastructure available. By using serverless offline plugins, changes become directly visible without any deployment needed and therefore the length of development cycles can be reduced significantly.

Questions, wishes, suggestions? Just drop a comment and I will see what I can do for you. 🙂

Tobias Schaber

Besides his core topic “distributed systems”, Tobias concentrates on automating infrastructure and complex systems, like for example elasticsearch-clusters. With him being part of a team, there is always a passionate advocate for agile software development on the scene, willingly pleading for agile methods.

Comment

Your email address will not be published. Required fields are marked *