aws-core-utils v8.1.3
Core utilities for working with Amazon Web Services (AWS), including ARNs, regions, stages, Lambdas, AWS errors, stream events, Kinesis, DynamoDB.DocumentClients, etc.
Currently includes:
- api-lambdas.js
- Utilities for generating
handler
functions for and for working with AWS Lambdas that are exposed via API Gateway
- For other AWS Lambdas that are NOT exposed via API Gateway, instead use the
aws-core-utils/other-lambdas
module
- other-lambdas.js
- Utilities for generating
handler
functions for and for working with "other" AWS Lambdas that are NOT exposed via
API Gateway and IDEALLY NOT triggered by a Kinesis or DynamoDB stream event source mapping
- For API Gateway exposed AWS Lambdas, instead use the
aws-core-utils/api-lambdas
module - For Kinesis triggered AWS Lambdas, instead consider using the
kinesis-stream-consumer
module - For DynamoDB triggered AWS Lambdas, instead consider using the
dynamodb-stream-consumer
module
- arns.js
- Utilities for working with Amazon Resource Names (ARNs)
- aws-errors.js
- Utilities for working with AWS errors
- contexts.js
- Utilities for configuring contexts for AWS Gateway exposed and other types of Lambdas
- dynamodb-doc-client-cache.js
- A module-scope cache of AWS.DynamoDB.DocumentClient instances by region for Lambda.
- dynamodb-doc-client-utils.js
- Utilities for working with AWS DynamoDB.DocumentClient.
- dynamodb-utils.js
- Utilities for working with AWS DynamoDB.
- kinesis-cache.js
- A module-scope cache of AWS.Kinesis instances by region for Lambda.
- kms-cache.js
- A module-scope cache of AWS.KMS instances by region for Lambda usage.
- kms-utils.js
- Utilities to simplify working with AWS.KMS instances.
- lambda-cache.js
- A module-scope cache of AWS.Lambda instances by region for use within Lambda functions.
- lambda-utils.js
- Utilities to simplify working with an AWS.Lambda instance
- lambdas.js
- Utilities for working with AWS Lambda, which enable extraction of function names, versions and, most importantly,
aliases from AWS contexts and their invoked function ARNs.
- Utility for failing non-API Gateway Lambda's callbacks with standard AppError errors if mapping of errors to HTTP status codes is needed
- regions.js
- Utilities for resolving the AWS region from various sources (primarily for AWS Lambda usage).
- stages.js
- Utilities for resolving or deriving the current stage (e.g. dev, qa, prod) from various sources
(primarily for AWS Lambda usage).
- Utilities for configuration of stage handling.
- Configurable and default functions for generating stage-qualified stream and resource names.
- Configurable and default functions for extracting stages from stage-qualified stream and resource names.
- stream-events.js
- Utilities for extracting information from AWS Kinesis and AWS DynamoDB stream events.
This module is exported as a Node.js module.
Installation
Using npm:
$ {sudo -H} npm i -g npm
$ npm i --save aws-core-utils
In Node.js:
- To use the
api-lambdas
module within your API Gateway exposed Lambda:
const apiLambdas = require('aws-core-utils/api-lambdas');
const isInstanceOf = require('core-functions/objects').isInstanceOf;
const appErrors = require('core-functions/app-errors');
const BadRequest = appErrors.BadRequest;
const createContext = () => ({});
const createOptions = () => require('./test/api-lambdas-context-options-2.json');
const createSettings = () => undefined;
function exampleFunction(event, context) { }
const opts = {
logRequestResponseAtLogLevel: 'INFO',
invalidRequestMsg: 'Invalid request ...',
failureMsg: 'Failed to ...',
successMsg: 'Finished ...'
};
exports.handler = apiLambdas.generateHandlerFunction(createContext, createSettings, createOptions, exampleFunction, opts);
exports.handler = (event, awsContext, callback) => {
const opts = {
};
let context = {};
try {
context = apiLambdas.configureHandlerContext(createContext, createSettings, createOptions, event, awsContext);
exampleFunction(event, context)
.then(response => {
context.info(opts.successMsg || 'Finished ...');
apiLambdas.succeedLambdaCallback(callback, response, event, context);
})
.catch(err => {
if (isInstanceOf(err, BadRequest) || appErrors.getHttpStatus(err) === 400) {
context.warn(opts.invalidRequestMsg || 'Invalid request ...', err.message);
} else {
context.error(opts.failureMsg || 'Failed to ...', err);
}
apiLambdas.failLambdaCallback(callback, err, event, context);
});
} catch (err) {
context.error('Failed to ...', err);
apiLambdas.failLambdaCallback(callback, err, event, context);
}
};
context.handler = {
useLambdaProxy: true,
defaultHeaders: {MyCustomHeader: 'MyCustomHeaderValue'},
allowedHttpStatusCodes: [400, 404, 418, 500, 508]
};
apiLambdas.failLambdaCallback(callback, new Error('Boom'), event, context);
- To use the AWS ARN utilities
const arns = require('aws-core-utils/arns');
const arnComponent = arns.getArnComponent(arn, index);
const arnPartition = arns.getArnPartition(arn);
const arnService = arns.getArnService(arn);
const arnRegion = arns.getArnRegion(arn);
const arnAccountId = arns.getArnAccountId(arn);
const arnResources = arns.getArnResources(arn);
assert(arnComponent && arnPartition && arnService && arnRegion && arnAccountId && arnResources);
- To use the AWS errors utilities
const awsErrors = require('aws-core-utils/aws-errors');
assert(awsErrors);
- To use the
contexts.js
module:
const contexts = require('aws-core-utils/contexts');
const context = {};
const standardOptions = require('my-standard-options.json');
const standardSettings = {};
contexts.configureStandardContext(context, standardSettings, standardOptions, awsEvent, awsContext);
const myCustomSettings = {myCustomSetting1: 1, myCustomSetting2: 2, myCustomFunction: () => {}};
console.log(`Irrelevant logging - only added to avoid unused function warning - ${myCustomSettings.myCustomFunction()}`);
const myCustomOptions = require('my-custom-options.json');
contexts.configureCustomSettings(context, myCustomSettings, myCustomOptions);
console.log(`context.custom = ${JSON.stringify(context.custom)}; myCustomFunction = ${JSON.stringify(context.custom.myCustomFunction)} `);
- To use the DynamoDB.DocumentClient cache to configure and cache an AWS DynamoDB.DocumentClient instance per region
const dynamoDBDocClientCache = require('aws-core-utils/dynamodb-doc-client-cache');
const context = {};
const logging = require('logging-utils');
logging.configureLogging(context);
const dynamoDBDocClientOptions = {
maxRetries: 0
};
const dynamoDBDocClient = dynamoDBDocClientCache.setDynamoDBDocClient(dynamoDBDocClientOptions, context);
dynamoDBDocClientCache.configureDynamoDBDocClient(context, dynamoDBDocClientOptions);
console.log(context.dynamoDBDocClient);
const dynamoDBDocClient1 = dynamoDBDocClientCache.getDynamoDBDocClient();
const dynamoDBDocClient2 = dynamoDBDocClientCache.getDynamoDBDocClient('us-west-2');
const optionsUsed1 = dynamoDBDocClientCache.getDynamoDBDocClientOptionsUsed();
const optionsUsed2 = dynamoDBDocClientCache.getDynamoDBDocClientOptionsUsed('us-west-1');
const deleted = dynamoDBDocClientCache.deleteDynamoDBDocClient('eu-west-1');
assert(dynamoDBDocClient && dynamoDBDocClient1 && dynamoDBDocClient2 && optionsUsed1 && optionsUsed2 && deleted);
- To use the Kinesis cache to configure and cache an AWS Kinesis instance per region
const kinesisCache = require('aws-core-utils/kinesis-cache');
const context = {};
const logging = require('logging-utils');
logging.configureLogging(context);
const kinesisOptions = {
maxRetries: 0
};
const kinesis = kinesisCache.setKinesis(kinesisOptions, context);
kinesisCache.configureKinesis(context, kinesisOptions);
console.log(context.kinesis);
const kinesis1 = kinesisCache.getKinesis();
const kinesis2 = kinesisCache.getKinesis('us-west-2');
const optionsUsed1 = kinesisCache.getKinesisOptionsUsed();
const optionsUsed2 = kinesisCache.getKinesisOptionsUsed('us-west-1');
const deleted = kinesisCache.deleteKinesis('eu-west-1');
assert(kinesis && kinesis1 && kinesis2 && optionsUsed1 && optionsUsed2 && deleted);
- To use the KMS cache to configure and cache an AWS KMS instance per region
const kmsCache = require('aws-core-utils/kms-cache');
const context = {};
const logging = require('logging-utils');
logging.configureLogging(context);
const kmsOptions = {
maxRetries: 0
};
const kms = kmsCache.setKMS(kmsOptions, context);
kmsCache.configureKMS(context, kmsOptions);
console.log(context.kms);
const kms1 = kmsCache.getKMS();
const kms2 = kmsCache.getKMS('us-west-2');
const optionsUsed1 = kmsCache.getKMSOptionsUsed();
const optionsUsed2 = kmsCache.getKMSOptionsUsed('us-west-1');
const deleted = kmsCache.deleteKMS('eu-west-1');
assert(kms && kms1 && kms2 && optionsUsed1 && optionsUsed2 && deleted);
- To use the AWS.KMS utilities
const kmsUtils = require('aws-core-utils/kms-utils');
const kms = new AWS.KMS({region: 'eu-west-1'});
const logging = require('logging-utils');
const logger = logging.configureLogging({});
const accountId = 'XXXXXXXXXXXX';
const kmsKeyAlias = 'aws/lambda';
const keyId = `arn:aws:kms:us-west-2:${accountId}:alias/${kmsKeyAlias}`;
const plaintext = 'Shhhhhhhhhhhhhhh';
kmsUtils.encryptKey(kms, keyId, plaintext, logger)
.then(ciphertextBase64 => console.log(JSON.stringify(ciphertextBase64)));
const ciphertextBase64 = '...';
kmsUtils.decryptKey(kms, ciphertextBase64, logger)
.then(plaintext => console.log(JSON.stringify(plaintext)));
const encryptParams = {KeyId: keyId, Plaintext: plaintext};
kmsUtils.encrypt(kms, encryptParams, logger)
.then(result => console.log(JSON.stringify(result)));
const decryptParams = {CiphertextBlob: new Buffer(ciphertextBase64, 'base64')};
kmsUtils.decrypt(kms, decryptParams, logger)
.then(result => console.log(JSON.stringify(result)));
- To use the Lambda cache to configure and cache an AWS Lambda instance per region
const lambdaCache = require('aws-core-utils/lambda-cache');
const context = {};
const logging = require('logging-utils');
logging.configureLogging(context);
const lambdaOptions = {
maxRetries: 0
};
const lambda = lambdaCache.setLambda(lambdaOptions, context);
lambdaCache.configureLambda(context, lambdaOptions);
console.log(context.lambda);
const lambda1 = lambdaCache.getLambda();
const lambda2 = lambdaCache.getLambda('us-west-2');
const optionsUsed1 = lambdaCache.getLambdaOptionsUsed();
const optionsUsed2 = lambdaCache.getLambdaOptionsUsed('us-west-1');
const deleted = lambdaCache.deleteLambda('eu-west-1');
assert(lambda && lambda1 && lambda2 && optionsUsed1 && optionsUsed2 && deleted);
- To use the AWS.Lambda utilities
const lambdaUtils = require('aws-core-utils/lambda-utils');
const lambda = new AWS.Lambda({region: 'eu-west-1'});
const params = {FunctionName: 'my-lambda-function'};
lambdaUtils.listEventSourceMappings(lambda, params, context)
.then(result => console.log(JSON.stringify(result)));
const params2 = {FunctionName: 'my-lambda-function', UUID: uuid, BatchSize: 99};
lambdaUtils.updateEventSourceMapping(lambda, params2, context)
.then(result => console.log(JSON.stringify(result)));
lambdaUtils.disableEventSourceMapping(lambda, 'my-lambda-function', uuid, context)
.then(result => console.log(JSON.stringify(result)));
- To use the Lambda utilities
const lambdas = require('aws-core-utils/lambdas');
const alias = lambdas.getAlias(awsContext);
const functionName = lambdas.getFunctionName(awsContext);
const functionVersion = lambdas.getFunctionVersion(awsContext);
const functionNameVersionAndAlias = lambdas.getFunctionNameVersionAndAlias(awsContext);
const invokedFunctionArn = lambdas.getInvokedFunctionArn(awsContext);
const invokedFunctionArnFunctionName = lambdas.getInvokedFunctionArnFunctionName(awsContext);
assert(alias && functionName && functionVersion && functionNameVersionAndAlias && invokedFunctionArn && invokedFunctionArnFunctionName);
- To get the current AWS region & configure it on a context
const regions = require('aws-core-utils/regions');
const region = regions.getRegion();
const context = {};
const failFast = true;
regions.configureRegion(context, failFast);
assert(context.region && typeof context.region === 'string');
- To use the stage utilities
const stages = require('aws-core-utils/stages');
const settings = undefined;
const options = require('aws-core-utils/stages-options.json');
stages.configureDefaultStageHandling(context);
const stageHandlingOptions = require('aws-core-utils/stages-options.json').stageHandlingOptions;
const otherSettings = undefined;
const otherOptions = require('aws-core-utils/test/sample-standard-options.json');
const forceConfiguration = false;
stages.configureDefaultStageHandling(context, stageHandlingOptions, otherSettings, otherOptions, forceConfiguration);
const stageHandlingSettings = stages.getDefaultStageHandlingSettings(options.stageHandlingOptions);
stages.configureStageHandling(context, stageHandlingSettings, stageHandlingOptions, otherSettings, otherOptions, forceConfiguration);
const stageHandlingSettings2 = {
envStageName: myEnvStageName,
customToStage: myCustomToStageFunction,
convertAliasToStage: myConvertAliasToStageFunction,
injectStageIntoStreamName: myInjectStageIntoStreamNameFunction,
extractStageFromStreamName: myExtractStageFromStreamNameFunction,
streamNameStageSeparator: myStreamNameStageSeparator,
injectStageIntoResourceName: myInjectStageIntoResourceNameFunction,
extractStageFromResourceName: myExtractStageFromResourceNameFunction,
resourceNameStageSeparator: myResourceNameStageSeparator,
injectInCase: myInjectInCase,
extractInCase: myExtractInCase,
defaultStage: myDefaultStage,
};
stages.configureStageHandling(context, stageHandlingSettings2, undefined, otherSettings, otherOptions, forceConfiguration);
stages.configureStageHandling(context, stageHandlingSettings, stageHandlingOptions, otherSettings, otherOptions, forceConfiguration);
const configured = stages.isStageHandlingConfigured(context);
const settingName = 'injectInCase';
const setting = stages.getStageHandlingSetting(context, settingName);
const functionSettingName = 'convertAliasToStage';
const fn = stages.getStageHandlingFunction(context, functionSettingName);
const context = {};
const stage = stages.resolveStage(awsEvent, awsContext, context);
const failFast = true;
stages.configureStage(context, awsEvent, awsContext, failFast);
assert(context.stage && typeof context.stage === 'string');
const qualifiedStreamName = 'TestStream_PROD';
const stage2 = stages.extractStageFromQualifiedStreamName(qualifiedStreamName, context);
assert(stage2 === 'prod');
const unqualifiedStreamName = 'TestStream';
const stageQualifiedStreamName = stages.toStageQualifiedStreamName(unqualifiedStreamName, stage2, context);
assert(stageQualifiedStreamName === 'TestStream_PROD');
const qualifiedTableName = 'TestTable_QA';
const stage3 = stages.extractStageFromQualifiedResourceName(qualifiedTableName, context);
assert(stage3 === 'qa');
const unqualifiedTableName = 'TestTable';
const stageQualifiedResourceName = stages.toStageQualifiedResourceName(unqualifiedTableName, stage3, context);
assert(stageQualifiedResourceName === 'TestTable_QA');
- To use the stream event utilities
const streamEvents = require('aws-core-utils/stream-events');
const eventSourceARNs = streamEvents.getEventSourceARNs(event);
const eventSourceStreamNames = streamEvents.getKinesisEventSourceStreamNames(event);
const eventSourceStreamName = streamEvents.getKinesisEventSourceStreamName(record);
const dynamoDBEventSourceTableName = streamEvents.getDynamoDBEventSourceTableName(record);
const tableNameAndStreamTimestamp = streamEvents.getDynamoDBEventSourceTableNameAndStreamTimestamp(record);
const dynamoDBEventSourceTableName1 = tableNameAndStreamTimestamp[0];
const dynamoDBEventSourceStreamTimestamp = tableNameAndStreamTimestamp[1];
try {
streamEvents.validateStreamEventRecord(record);
streamEvents.validateKinesisStreamEventRecord(record);
streamEvents.validateDynamoDBStreamEventRecord(record);
} catch (err) {
}
Unit tests
This module's unit tests were developed with and must be run with tape. The unit tests have been tested on Node.js v6.10.3.
Install tape globally if you want to run multiple tests at once:
$ npm install tape -g
Run all unit tests with:
$ npm test
or with tape:
$ tape test/*.js
See the package source for more details.
Changes
See CHANGES.md