/es2017-lambda-boilerplate

An ES2017 boilerplate for AWS Lambda (Node.js 6.10)

Primary LanguageJavaScriptMIT LicenseMIT

es2017-lambda-boilerplate

es2017-lambda-boilerplate

Travis CI Greenkeeper badge GitHub The MIT License

This is a boilerplate for AWS Lambda Node.js 6.10.0 functions, which allows you to use the latest JavaScript ES2017/ES8 features within a Lambda function.

This boilerplate adds support for the following most commonly used JavaScript features that are not natively supported on AWS Lambda:

Feature Supported?
ES2016/ES7
Exponentiation operator (**)
Array.prototype.includes
ES2017/ES8
Object.values, Object.entries
Trailing commas in function syntax
async/await
ESNEXT
Object rest/spread properties

Note: Only features which are not normally available on AWS Lambda Node.js 6.10.0 are listed. Most ES2015/ES6 features and earlier are supported.

Usage

Edit your Lambda function under src/main.js, and run:

npm run package

This will create an artifact.zip file which you can upload to AWS Lambda.

Testing

You can run automated tests for your Lambda function inside of a Docker container using docker-lambda:

npm run test

The test runner used is Jest (with Jasmine). All files in the test/ directory which end with .test.js will be interpreted as a test suite.

This also requires Docker to be installed on your host; see the docs for docker-lambda for more instructions.

Specification tests

In order to ensure that the Babel configuration works and is following the spec, the boilerplate also runs several automated tests to catch any Babel misconfigurations.

  • Functional testing: Runs the relevant spec tests from Test262 (actual tests taken from node.green) on docker-lambda to mock the AWS Lambda environment
  • Snapshot testing: Unit testing strategy by storing snapshots of Babel-transformed source code and running unit tests against them

You can find the spec tests under spec/functional and spec/snapshot respectively.

If you are not going to modify .babelrc, you can choose to skip these tests by omitting the npm run spec script in .travis.yml. This will help to speed up your builds by a bit.

Deployment

You can automatically deploy to AWS Lambda locally or through CI (e.g. Travis), as long as you provide an access key for an IAM user that has write access to AWS Lambda.

npm run deploy

See Environment variables for the list of environment variables that are required for deployment.

Using the AWS SDK

You can write Lambda functions that make use of the AWS SDK by simply import-ing aws-sdk. The package is installed globally within the AWS Lambda environment, so you don't need to add it to your package.json.

Also make sure that your function has Internet connectivity (i.e. not within a VPC without a NAT gateway). The internetConnectivityTest.js utility is included to help to debug such problems early when deploying to AWS Lambda.

Environment variables

The following environment variables are supported:

  • AWS_ACCESS_KEY_ID: IAM user access key ID
  • AWS_SECRET_ACCESS_KEY: IAM user secret access key
  • AWS_REGION: AWS region where the Lambda function resides in
  • LAMBDA_FUNCTION_NAME: Name or ARN of the Lambda function

This will work if you store it in a .env file in the root of the project (see dotenv), or if you define it within Travis CI itself (see Travis docs).

Why?

Latest ES2017 features

Even though Lambda supposedly supports Node.js 6.10.0, not all JavaScript features are supported. www.whatdoeslambdasupport.com has a comprehensive list of what is supported and what are not.

This boilerplate adds support for the most commonly used features that are not available on Node 6.10.0 or AWS Lambda, such as async/await when used with the AWS SDK:

const EC2 = new AWS.EC2();
const Route53 = new AWS.Route53();

// Get instance by ID.
const instances = await EC2.describeInstances({ InstanceIds: 'i-abcdef01' }).promise();

// Get public IP address.
const publicIpAddress = instances.Reservations[0].Instances[0].PublicIpAddress;

// Do something else with the IP address...
await Route53.changeResourceRecordSets({
    // ...
}).promise();

Run automated tests locally/through CI

Instead of testing your Lambda function by uploading to AWS Lambda every single time, running automated tests in conjunction with CI is a better option. By using Docker to mock the AWS Lambda environment locally, you can write test cases to verify the correctness of your function, given an input (the Lambda event):

import run from './util/runner';

it('should work', function() {
    // Sample event from SNS.
    const event = {
        Records: [
            {
                EventVersion: '1.0',
                EventSource: 'aws:sns',
                Sns: {
                    MessageId: '95df01b4-ee98-5cb9-9903-4c221d41eb5e',
                    Message: 'Hello from SNS!',
                    ...
                },
            },
        ],
    };

    // Run the Lambda function against this event.
    const result = run(event);

    expect(result).toEqual(true);
});

This strategy also does not utilise your AWS Lambda invocation credits - meaning you are free to run as many tests as often as you like!

Acknowledgements

This boilerplate was first inspired from this post by Jesse Cascio.

License

MIT