--------- AWS Lambda code ---------
Here’s the utils part of my sdk library
'use strict';
const AWS = require('aws-sdk');
// ----------------------------------------------------------------------------------------------------------------
const gleanFromParameters_missing = (parameters) => {
console.info(`NOTE: you may pass a function 'gleanFromParameters(parameters)
into 'configForAWS({ environment, event, context, gleanFromParameters })
to extract info from the object: { environment, event, context }`);
}
// create a configuration for our task
// https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Config.html#update-property
const configForAWS = ({
environment = { deepFail: false, deepResults: false, deepDebug: false },
event = {},
context = {},
gleanFromParameters = gleanFromParameters_missing
}) => {
try {
let parameters = { environment, event, context };
parameters = gleanFromParameters(parameters);
sanityCheckEnvironment(environment);
const awsConfig = { region: environment.region };
console.debug(`configForAWS, call: AWS.config.update`, awsConfig);
AWS.config.update(awsConfig);
return Promise.resolve({
...parameters,
awsConfig
});
} catch (err) {
throw new Error(`configForAWS threw: ${err.message || err}`);
}
}
// sanity check environment -- nothing can be empty
const sanityCheckEnvironment = (env) => {
for (const fldName in env) {
if (env[fldName] === null || env[fldName] === undefined) {
throw new Error(`configForAWS, ${fldName} is empty in environment`);
}
}
}
// ----------------------------------------------------------------------------------------------------------------
// log our results, with the return value from S3
const reportResults = (parameters) => {
const { environment } = { ...parameters };
const { deepResults } = { ...environment };
try {
if (deepResults) {
console.debug(`reportResults parameters:`, JSON.stringify(parameters, null, 2));
}
console.log(`completed with success`);
return parameters;
} catch (err) {
throw new Error(`reportResults threw: ${err.message || err}`);
}
}
// ----------------------------------------------------------------------------------------------------------------
const CallbackSuccessWithText = function (callback, message) {
const response = {
statusCode: 200,
body: message
};
return callback(null, response);
};
// ----------------------------------------------------------------------------------------------------------------
const CallbackErrorResponse = function (_a) {
const err = _a.err, fnName = _a.fnName, callback = _a.callback;
console.error(fnName + " threw: ", err);
if (err instanceof HTMLError) {
return callback(null, err.htmlResponse());
}
const unspecifiedErr = new InternalError(function () { return err.message || err; });
return callback(null, unspecifiedErr.htmlResponse());
};
// ----------------------------------------------------------------------------------------------------------------
module.exports = {
configForAWS,
reportResults,
CallbackSuccessWithText,
CallbackErrorResponse,
};
Here’s the S3 part of my sdk library
'use strict';
const S3 = require('aws-sdk/clients/s3');
// how long to wait between tests
const SECONDS_BETWEEN_S3_CHECKS = 5;
// how long to wait before failure
const SECONDS_BEFORE_S3_FAIL = 20;
// https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#getSignedUrl-property
const doGetSignedUrl = (parameters) => {
try {
const { awsConfig } = { ...parameters };
const s3 = new S3(awsConfig);
return new Promise((resolve, reject) => {
try {
const params = paramsForDoGetSignedUrl(parameters);
logParamsForDoGetSignedUrl(params, parameters);
s3.getSignedUrl(params.Operation, params.Params, (err, getSignedUrlResult) => {
if (err) {
reject({ message: err });
}
resolve({
...parameters,
doGetSignedUrlResult: getSignedUrlResult
});
});
}
catch (err) {
reject(err.message || err);
}
});
} catch (err) {
throw new Error(`doGetSignedUrl threw: ${err.message || err}`);
}
}
// log safely
const logParamsForDoGetSignedUrl = (paramBlock, parameters) => {
const { environment } = { ...parameters };
const { deepDebug } = { ...environment };
if (deepDebug) {
console.debug(`---------> doGetSignedUrl, call: s3.getSignedUrl`, JSON.stringify(paramBlock, null, 2));
} else {
const loggableParamBlock = JSON.parse(JSON.stringify(paramBlock));
console.debug(`doGetSignedUrl, call: s3.headBucket, paramBlock:`, loggableParamBlock);
}
}
const buildS3GetSignedUrlOperation_missing = () => {
throw new Error(`ERROR: a function 'buildS3GetSignedUrlOperation(parameters)' is missing from the parameters to build the S3 operation`);
}
const buildS3GetSignedUrlParams_missing = () => {
throw new Error(`NOTE: a function 'buildS3GetSignedUrlParams(parameters)' is missing from the parameters to build the S3 params`);
}
// create S3 params for writing the variable
const paramsForDoGetSignedUrl = (parameters) => {
const {
buildS3GetSignedUrlOperation = buildS3GetSignedUrlOperation_missing,
buildS3GetSignedUrlParams = buildS3GetSignedUrlParams_missing,
} = { ...parameters };
return {
Operation: buildS3GetSignedUrlOperation(parameters),
Params: buildS3GetSignedUrlParams(parameters)
};
}
// ----------------------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------------
// connect to s3 and check to see if a bucket exists
// https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#headBucket-property
const doHeadBucket = (parameters) => {
try {
const { awsConfig } = { ...parameters };
const s3 = new S3(awsConfig);
return new Promise((resolve, reject) => {
try {
const params = paramsForDoHeadBucket(parameters);
logParamsForDoHeadBucket(params, parameters);
s3.headBucket(params, (err, s3Result) => {
if (err) {
if (/NotFound/.test(err)) {
resolve(parameters); // resolve with no result, this is ok -- anything else is bust
}
if (/Forbidden/.test(err)) {
resolve(parameters); // resolve with no result, this is ok -- anything else is bust
}
reject({ message: err });
}
resolve({
...parameters,
doHeadBucketResult: {
...s3Result,
bucketName: params.Bucket
}
});
});
}
catch (err) {
reject(err.message || err);
}
});
} catch (err) {
throw new Error(`doHeadBucket threw: ${err.message || err}`);
}
}
// log safely
const logParamsForDoHeadBucket = (paramBlock, parameters) => {
const { environment } = { ...parameters };
const { deepDebug } = { ...environment };
if (deepDebug) {
console.debug(`---------> doHeadBucket, call: s3.headBucket`, JSON.stringify(paramBlock, null, 2));
} else {
const loggableParamBlock = JSON.parse(JSON.stringify(paramBlock));
console.debug(`doHeadBucket, call: s3.headBucket, paramBlock:`, loggableParamBlock);
}
}
const buildS3HeadBucketName_missing = () => {
throw new Error(`ERROR: a function 'buildS3HeadBucketName(parameters)' is missing from the parameters to build the S3 bucket you wish to head`);
}
// create S3 params for writing the variable
const paramsForDoHeadBucket = (parameters) => {
const {
buildS3HeadBucketName = buildS3HeadBucketName_missing,
} = { ...parameters };
return {
Bucket: buildS3HeadBucketName(parameters),
};
}
// ----------------------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------------
// connect to s3 and create a bucket
// https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#createBucket-property
const doCreateBucket = (parameters) => {
try {
const { awsConfig } = { ...parameters };
const s3 = new S3(awsConfig);
return new Promise((resolve, reject) => {
try {
const params = paramsForDoCreateBucket(parameters);
logParamsForDoCreateBucket(params, parameters);
s3.createBucket(params, (err, s3Result) => {
if (err) {
reject({ message: err });
}
resolve({
...parameters,
doCreateBucketResult: s3Result
});
});
}
catch (err) {
reject(err.message || err);
}
});
} catch (err) {
throw new Error(`doCreateBucket threw: ${err.message || err}`);
}
}
// log safely
const logParamsForDoCreateBucket = (paramBlock, parameters) => {
const { environment } = { ...parameters };
const { deepDebug } = { ...environment };
if (deepDebug) {
console.debug(`---------> doCreateBucket, call: s3.createBucket`, JSON.stringify(paramBlock, null, 2));
} else {
const loggableParamBlock = JSON.parse(JSON.stringify(paramBlock));
console.debug(`doCreateBucket, call: s3.createBucket, paramBlock:`, loggableParamBlock);
}
}
const buildS3CreateBucketName_missing = () => {
throw new Error(`ERROR: a function 'buildS3CreateBucketName(parameters)' is missing from the parameters to build the S3 bucket you wish to create`);
}
// create S3 params for writing the variable, us-east-1 was aws' first and needs special recognition
const paramsForDoCreateBucket = (parameters) => {
const {
environment, buildS3CreateBucketName = buildS3CreateBucketName_missing,
} = { ...parameters };
return (environment.region === 'us-east-1') ? {
Bucket: buildS3CreateBucketName(parameters),
} : {
Bucket: buildS3CreateBucketName(parameters),
CreateBucketConfiguration: {
LocationConstraint: environment.region
}
};
}
// ----------------------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------------
// connect to s3 and create a bucket
// https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#putBucketVersioning-property
const doPutBucketVersioning = (parameters) => {
try {
const { awsConfig } = { ...parameters };
const s3 = new S3(awsConfig);
return new Promise((resolve, reject) => {
try {
const params = paramsForDoPutBucketVersioning(parameters);
logParamsForDoPutBucketVersioning(params, parameters);
s3.putBucketVersioning(params, (err, s3Result) => {
if (err) {
reject({ message: err });
}
resolve({
...parameters,
doPutBucketVersioningResult: s3Result
});
});
}
catch (err) {
reject(err.message || err);
}
});
} catch (err) {
throw new Error(`doPutBucketVersioning threw: ${err.message || err}`);
}
}
// log safely
const logParamsForDoPutBucketVersioning = (paramBlock, parameters) => {
const { environment } = { ...parameters };
const { deepDebug } = { ...environment };
if (deepDebug) {
console.debug(`---------> doPutBucketVersioning, call: s3.putBucketVersioning`, JSON.stringify(paramBlock, null, 2));
} else {
const loggableParamBlock = JSON.parse(JSON.stringify(paramBlock));
console.debug(`doPutBucketVersioning, call: s3.putBucketVersioning, paramBlock:`, loggableParamBlock);
}
}
const buildS3VersioningBucketName_missing = () => {
throw new Error(`ERROR: a function 'buildS3VersioningBucketName(parameters)' is missing from the parameters to build the S3 bucket you wish to create`);
}
// create S3 params for writing the variable
const paramsForDoPutBucketVersioning = (parameters) => {
const {
buildS3VersioningBucketName = buildS3VersioningBucketName_missing,
} = { ...parameters };
return {
Bucket: buildS3VersioningBucketName(parameters),
VersioningConfiguration: {
MFADelete: "Disabled",
Status: "Enabled"
}
};
}
// ----------------------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------------
// https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#putBucketCors-property
const doPutBucketCors = (parameters) => {
try {
const { awsConfig } = { ...parameters };
const s3 = new S3(awsConfig);
return new Promise((resolve, reject) => {
try {
const params = paramsForDoPutBucketCors(parameters);
logParamsForDoPutBucketCors(params, parameters);
s3.putBucketCors(params, (err, s3Result) => {
if (err) {
reject({ message: err });
}
resolve({
...parameters,
doPutBucketCorsResult: s3Result
});
});
}
catch (err) {
reject(err.message || err);
}
});
} catch (err) {
throw new Error(`doPutBucketCors threw: ${err.message || err}`);
}
}
// log safely
const logParamsForDoPutBucketCors = (paramBlock, parameters) => {
const { environment } = { ...parameters };
const { deepDebug } = { ...environment };
if (deepDebug) {
console.debug(`---------> doPutBucketCors, call: s3.putBucketCors`, JSON.stringify(paramBlock, null, 2));
} else {
const loggableParamBlock = JSON.parse(JSON.stringify(paramBlock));
console.debug(`doPutBucketCors, call: s3.putBucketCors, paramBlock:`, loggableParamBlock);
}
}
const buildS3CorsBucketName_missing = () => {
throw new Error(`ERROR: a function 'buildS3CorsBucketName(parameters)' is missing from the parameters to build the S3 bucket you wish to create`);
}
const buildS3CorsBucketConfig_missing = () => {
throw new Error(`ERROR: a function 'buildS3CorsBucketConfig(parameters)' is missing from the parameters to build the S3 bucket cors config`);
}
// create S3 params for writing the variable
const paramsForDoPutBucketCors = (parameters) => {
const {
buildS3CorsBucketName = buildS3CorsBucketName_missing,
buildS3CorsBucketConfig = buildS3CorsBucketConfig_missing,
} = { ...parameters };
return {
Bucket: buildS3CorsBucketName(parameters),
CORSConfiguration: buildS3CorsBucketConfig(parameters)
};
}
// ----------------------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------------
// connect to s3 and create a bucket
// https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#putPublicAccessBlock-property
const doPutPublicAccessBlock = (parameters) => {
try {
const { awsConfig } = { ...parameters };
const s3 = new S3(awsConfig);
return new Promise((resolve, reject) => {
try {
const params = paramsForDoPutPublicAccessBlock(parameters);
logParamsForDoPutPublicAccessBlock(params, parameters);
s3.putPublicAccessBlock(params, (err, s3Result) => {
if (err) {
reject({ message: err });
}
resolve({
...parameters,
doPutPublicAccessBlockResult: s3Result
});
});
}
catch (err) {
reject(err.message || err);
}
});
} catch (err) {
throw new Error(`doPutPublicAccessBlock threw: ${err.message || err}`);
}
}
// log safely
const logParamsForDoPutPublicAccessBlock = (paramBlock, parameters) => {
const { environment } = { ...parameters };
const { deepDebug } = { ...environment };
if (deepDebug) {
console.debug(`---------> doPutPublicAccessBlock, call: s3.putPublicAccessBlock`, JSON.stringify(paramBlock, null, 2));
} else {
const loggableParamBlock = JSON.parse(JSON.stringify(paramBlock));
console.debug(`doPutPublicAccessBlock, call: s3.putPublicAccessBlock, paramBlock:`, loggableParamBlock);
}
}
const buildS3PublicAccessBucketName_missing = () => {
throw new Error(`ERROR: a function 'buildS3PublicAccessBucketName(parameters)' is missing from the parameters to build the S3 bucket you wish to create`);
}
// create S3 params for writing the variable
const paramsForDoPutPublicAccessBlock = (parameters) => {
const {
buildS3PublicAccessBucketName = buildS3PublicAccessBucketName_missing,
} = { ...parameters };
return {
Bucket: buildS3PublicAccessBucketName(parameters),
PublicAccessBlockConfiguration: {
BlockPublicAcls: true,
BlockPublicPolicy: true,
IgnorePublicAcls: true,
RestrictPublicBuckets: true
}
};
}
// ----------------------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------------
// ensure the bucket exists and is ready
const doEnsureBucket = (parameters) => {
try {
return new Promise((resolve, reject) => {
doHeadBucket(parameters) // if bucket exists
.then(parameters => {
const { doHeadBucketResult } = { ...parameters };
const { bucketName } = { ...doHeadBucketResult };
if (bucketName) {
resolve(parameters); // then the bucket is there
} else {
doCreateBucket(parameters) // otherwise create it, which we have to wait for
.then(parameters => {
const bucketCreateFailedAfter = new Date().getTime() + (1000 * SECONDS_BEFORE_S3_FAIL); // we won't wait too long...
const myWatcher = setInterval(() => {
doHeadBucket(parameters) // is is there yet?
.then(parameters => {
const { doHeadBucketResult } = { ...parameters };
const { bucketName } = { ...doHeadBucketResult };
if (bucketName) {
clearInterval(myWatcher);
resolve(parameters); // then we succeded
}
})
.catch(err => {
if (new Date().getTime() > bucketCreateFailedAfter) {
clearInterval(myWatcher);
reject(`doEnsureBucket call rejected: ${err.message || err}`); // we waited, and it never showed up
}
})
}, 1000 * SECONDS_BETWEEN_S3_CHECKS);
})
.catch(err => {
reject(`doCreateBucket call threw: ${err.message || err}`); // we could not create it
});
}
})
.catch(err => {
reject(`doHeadBucket call threw: ${err.message || err}`); // we could not find it
});
});
} catch (err) {
throw new Error(`doEnsureBucket threw: ${err.message || err}`);
}
}
// ----------------------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------------
// connect to s3 and write these objects [Value] into a file as JSON
// https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#putObject-property
const doPutObject = (parameters) => {
try {
const { awsConfig } = { ...parameters };
const s3 = new S3(awsConfig);
return new Promise((resolve, reject) => {
try {
const params = paramsForDoPutObject(parameters);
logParamsForDoPutObject(params, parameters);
s3.putObject(params, (err, s3Result) => {
if (err) {
reject({ message: err });
}
resolve({
...parameters,
doPutObjectResult: s3Result
});
});
}
catch (err) {
reject(err.message || err);
}
});
} catch (err) {
throw new Error(`doPutObject threw: ${err.message || err}`);
}
}
// log safely
const logParamsForDoPutObject = (paramBlock, parameters) => {
const { environment } = { ...parameters };
const { deepDebug } = { ...environment };
if (deepDebug) {
console.debug(`---------> doPutObject, call: s3.putObject`, JSON.stringify(paramBlock, null, 2));
} else {
const loggableParamBlock = JSON.parse(JSON.stringify(paramBlock));
loggableParamBlock.Body = deepDebug ? loggableParamBlock.Body : `<redacted>`;
console.debug(`doPutObject, call: s3.putObject, paramBlock:`, loggableParamBlock);
}
}
const buildS3PutObjectBucketName_missing = () => {
throw new Error(`ERROR: a function 'buildS3PutObjectBucketName(parameters)' is missing from the parameters to build the S3 bucket you wish to create`);
}
const buildS3PutObjectS3Key_missing = () => {
throw new Error(`ERROR: a function 'buildS3PutObjectS3Key(parameters)' is missing from the parameters to build the S3 bucket you wish to create`);
}
const buildS3PutObjectS3ReadyData_missing = () => {
throw new Error(`ERROR: a function 'buildS3PutObjectS3ReadyData(parameters)' is missing from the parameters to build the S3 bucket you wish to create`);
}
// create S3 params for writing the variable
const paramsForDoPutObject = (parameters) => {
const {
buildS3PutObjectS3ReadyData = buildS3PutObjectS3ReadyData_missing,
buildS3PutObjectBucketName = buildS3PutObjectBucketName_missing,
buildS3PutObjectS3Key = buildS3PutObjectS3Key_missing,
} = { ...parameters };
const s3ReadyData = buildS3PutObjectS3ReadyData(parameters)
return {
Body: Buffer.from(s3ReadyData, 'utf8'),
Bucket: buildS3PutObjectBucketName(parameters),
Key: buildS3PutObjectS3Key(parameters),
};
}
// ----------------------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------------
// connect to s3 and read the object
// https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#getObject-property
const doGetObject = (parameters) => {
try {
const { awsConfig } = { ...parameters };
const s3 = new S3(awsConfig);
return new Promise((resolve, reject) => {
try {
const params = paramsForGetObject(parameters);
logParamsForGetObject(params, parameters);
s3.getObject(params, (err, s3Response) => {
if (err) {
console.error(`AWS.clients.s3.getObject errored:`, err.stack);
reject({
...parameters,
error: err.message,
stack: err.stack
});
}
resolve({
...parameters,
s3Response
});
});
}
catch (err) {
reject(err.message || err);
}
});
} catch (err) {
throw new Error(`doGetObject threw: ${err.message || err}`);
}
}
// log safely
const logParamsForGetObject = (paramBlock, parameters) => {
console.debug(`doGetObject, call: s3.getObject`, paramBlock);
}
const buildS3GetObjectBucketName_missing = () => {
throw new Error(`ERROR: a function 'buildS3GetObjectBucketName(parameters)' is missing from the parameters to build the S3 bucket you wish to create`);
}
const buildS3GetObjectS3Key_missing = () => {
throw new Error(`ERROR: a function 'buildS3GetObjectS3Key(parameters)' is missing from the parameters to build the S3 bucket you wish to create`);
}
// create S3 params for reading the params file
const paramsForGetObject = (parameters) => {
const {
buildS3GetObjectBucketName = buildS3GetObjectBucketName_missing,
buildS3GetObjectS3Key = buildS3GetObjectS3Key_missing,
} = { ...parameters };
return {
Bucket: buildS3GetObjectBucketName(parameters),
Key: buildS3GetObjectS3Key(parameters),
};
}
// ----------------------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------------
module.exports = {
doCreateBucket,
doEnsureBucket,
doGetObject,
doGetSignedUrl,
doHeadBucket,
doPutBucketCors,
doPutObject,
doPutPublicAccessBlock,
doPutBucketVersioning,
};
Cheers, you made it this far !!
Hope it all helps !!
The End.