sls-config-parser parses serverless.yml files so that its values can be used locally in JS code during development, including automatically setting up environment variables. Its main usage is to set up the environment variables (including the access key and secret from the ~/.aws/credentials
as well as the region from the ~/.aws/config
) locally so it is possible to test functions locally. Setting up the environment variables is done in a package.json script as follow:
"scripts": {
"start": "node -r sls-config-parser/setenv index.js --inclcreds --stage prod"
}
This script sets up the environment variables based on the profile defined in the serverless.yml
file and the credentials defined in the ~/.aws/credentials
and ~/.aws/config
the file.
WARNING: The package is in beta. Limitations:
- Not tested on Windows.
- Only works with YAML files (JSON support coming soon).
- No support for CloudFormation intrinsic functions yet (e.g., Ref, !Sub, !Join).
npm i sls-config-parser
Dev dependency VS App dependency: Depending on your use case, install it as a dev dependency or as an app dependency. The dev dependency case occurs when, for example, you're only interested in setting environment variables based on your .aws/credentials and your serverless.yml.
Assuming there is a serverless.yml
file in your root folder:
const { Config } = require('sls-config-parser')
const defaultCfg = new Config()
const stagingCfg = new Config({ stage: 'staging' })
const prodCfg = new Config({ stage: 'prod' })
const customCfg = new Config({ stage: 'prod', _path:'../path-to-another-config/some-other.yml' })
console.log('DEFAULT CONFIG:')
console.log(defaultCfg.config())
console.log('STAGING CONFIG:')
console.log(stagingCfg.config())
console.log('PROD CONFIG:')
console.log(prodCfg.config())
console.log('CUSTOM CONFIG:')
console.log(customCfg.config())
Let's imagine we have the following serverless.yml
file:
service: graphql
custom:
stage: ${opt:stage, 'dev'}
dynamoDB:${file(./config/local.yml)}
provider:
name: aws
runtime: nodejs10.x
region: ap-southeast-2
profile: fairplay
stage: ${self:custom.stage}
environment:
DATA_01: hello ${self:provider.stage}
DATA_02: boom boom
functions:
graphql:
handler: handler.handler
events:
- http:
path: /
method: ANY
environment:
GRAPHQL_ENV_01: graphql_01
GRAPHQL_ENV_02: graphql_02
rest:
handler: handler.rest
events:
- http:
path: /rest
method: ANY
environment:
REST_ENV_01: rest_01
REST_ENV_02: rest_02
resources:
Resources:
UserTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: user_${self:provider.stage}
AttributeDefinitions:
- AttributeName: id
AttributeType: N
- AttributeName: username
AttributeType: S
- AttributeName: data
AttributeType: M
KeySchema:
- AttributeName: id
KeyType: N
ProvisionedThroughput: ${self:custom.dynamoDB.${self:provider.stage}ProvisionedThroughput}
Tags:
- Key: Type
Value: test
- Key: Name
Value: graphql
const { Config } = require('sls-config-parser')
const defaultCfg = new Config()
// EXAMPLE 01: Returns an object with all the environment variables (both global and local to all functions).
// For example: env.DATA_01 -> 'hello dev', env.GRAPHQL_ENV_01 -> 'graphql_01', env.REST_ENV_01 -> 'rest_01'
console.log(defaultCfg.env())
// EXAMPLE 02: Returns the same data as above, but as an array rather than an object.
// For example: [{ name: 'DATA_01', value: 'hello dev' }, { name:'GRAPHQL_ENV_01', value: 'graphql_01' }, ...]
console.log(defaultCfg.env({ format:'array' }))
// EXAMPLE 03: Returns the same data as #01, but only focus on the global variables and the 'graphql' function variables.
console.log(defaultCfg.env({ functions:['graphql'] }))
// EXAMPLE 04: Returns the same data as #03, but ignore the global variables.
console.log(defaultCfg.env({ functions:['graphql'], ignoreGlobal:true }))
// EXAMPLE 05: Returns the global variables only.
console.log(defaultCfg.env({ ignoreFunctions:true }))
// EXAMPLE 06: Returns the same data as #01 with the additionnal AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY defined
// in the ~/.aws/credentials file. If there are multiple profiles in the credentials file, sls-config-parser uses the
// profile defined under the provider.profile property in the serverless.yml file (in our case, that profile is called
// 'fairplay').
// For example: env.AWS_ACCESS_KEY_ID -> 'SHWKHSKWHKHKWSW', env.AWS_SECRET_ACCESS_KEY -> 'dbwjdejewgdewdjjgjewdgewdg'
console.log(defaultCfg.env({ inclAccessCreds:true }))
// EXAMPLE 07: Same as #06, but with a custom credentials file.
console.log(defaultCfg.env({ inclAccessCreds:true, awsCreds:'../path-to-other-creds/other-creds-file' }))
This is the original purpose of this package. This section contains some context in the Why is it important? section. If you're already aware of the running a Lambda locally, you can jump to the Setting things up section.
To use the nodeJS AWS SDK (e.g., using it to read or write to a DynamoDB), it must be configured with the access key and access secret or with an IAM policy. The easiest way to perform this is to explicitly set it up in your code:
const AWS = require('aws-sdk')
AWS.config = new AWS.Config({ accessKeyId:'WHIWHHIHH', secretAccessKey: 'debwjkdbewkjbdkjedbk', region:'ap-southeast-2' })
const db = new AWS.DynamoDB.DocumentClient({ apiVersion: '2012-08-10' })
This code makes it straightforward to test locally. However, the above approach is not recommended, as it explicitly exposes the access key and secret. A nefarious conributor could use those credentials to exploit your system.
The recommended approach is to configure an IAM policy in the iamRoleStatements
property of the provider
section in the serverless.yml
. Once this is done, the AWS SDK does not require explicit access key and secret, as those are safely set up as environment variables on your Lambda at deployment time. You can then simply use this instead:
const AWS = require('aws-sdk')
const db = new AWS.DynamoDB.DocumentClient({ apiVersion: '2012-08-10' })
And yet, this creates another issue: How do you test this code locally? The answer to this question is easy to understand, but annoying to implement, and that where this package comes into play. To make the above code work locally, the following environment variables must be set up:
The first two variables are located under the ~/.aws/credentials
file while the third one is under the ~/.aws/config
. You could manually set those variables in a start script in your package.json as follow:
"scripts": {
"start": "AWS_ACCESS_KEY_ID=******* AWS_SECRET_ACCESS_KEY=********** AWS_REGION=ap-southeast-2 node index.js"
}
However, this is far from being flexible. Besides, there might be more environment variables to set up based on your serverless.yml
file (which could also define a specific provider.profile
value influencing the value of the access key and secret). Ideally, those variables are automatically set up based on the correct selected stage of the serverless.yml
file. That's exactly what this package offers.
PREREQUISITE: The following assumes that you have a
~/.aws/credentials
and a~/.aws/config
file properly configured (i.e., the profile defined in theserverless.yml
under theprovider.profile
property exists).
To set up all the environment variables in your local environment, add a script in your package.json similar to this:
"scripts": {
"dev": "node -r sls-config-parser/setenv index.js --inclcreds --stage dev"
}
To know more about this script's API, please refer to the
sls-config-parser/setenv
API section of the Annexes.
To run your Lambda locally, just run:
npm run dev
Sometimes you may need to overide some serverless.yml properties in your package.json scripts (e.g., you wish to set up a specific provider's profile without setting one up in the serverless.yml file). You can achieve this with the --force
option as follow:
"scripts": {
"start": "node -r sls-config-parser/setenv index.js --inclcreds --stage prod --force 'provider.profile=neap;provider.region=ap-southeast-2'"
}
sls-config-parser/setenv
API"scripts": {
"dev": "node -r sls-config-parser/setenv index.js --inclcreds --stage dev"
}
The -r
options means require. This requires the JS file located under the path sls-config-parser/setenv.js
. This file executes a function which takes the options --inclcreds
and --stage dev
and sets up the environment variables defined in the serverless.yml
and in the ~/.aws/credentials
and a ~/.aws/config
files. Once this is done, the index.js
file is executed.
The options for the sls-config-parser/setenv.js
function are:
--inclcreds
: If specified, this means the environment variables defined in the ~/.aws/credentials
file and in the ~/.aws/config
file must be set up. Otherwise, only the variables of the serverless.yml
are included.--stage <stage-name>
: Defines which stage must be used in the serverless.yml
.--path <path-value>
: Specifies another location for the serverless.yml
.We are Neap, an Australian Technology consultancy powering the startup ecosystem in Sydney. We simply love building Tech and also meeting new people, so don't hesitate to connect with us at https://neap.co.
Our other open-sourced projects:
Copyright (c) 2017-2019, Neap Pty Ltd. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NEAP PTY LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.