Skip to content

Instantly share code, notes, and snippets.

@mrosata
Last active January 8, 2018 17:11
Show Gist options
  • Save mrosata/4b478ab5ee3ab03c87d32ee321ef8235 to your computer and use it in GitHub Desktop.
Save mrosata/4b478ab5ee3ab03c87d32ee321ef8235 to your computer and use it in GitHub Desktop.
Generates code to wrap entire AWS service apis as functions or methods returning Promises. Setup: `yarn add ramda yargs`
#!/usr/bin/node
////////////////////////////////////////////////////////////////////////////////
//// Create AWS Service Promisified Functions
//// @author Michael Rosata
////
//// @dependencies ramda, yargs
////
//// @desc
//// Returns the code that would wrap every method from one AWS Service into
//// functions that return Promises rather than those returning Node style
//// callbacks.
//// The new functions are named similar to their original counterparts.
//// IE:
//// S3.getBucket() --> s3GetBucket()
//// It can also generate an entire module.export = {...} for the service.
//// in which case `s3getBucket` becomes `s3.getBucket`
////
//// @uses
//// node ./denode-aws-service-code.js --service s3
//// node ./denode-aws-service-code.js --service s3 --as-export
//// node ./denode-aws-service-code.js --service sqs --namespace SQS
//// node ./denode-aws-service-code.js --service sqs --promisify customFnName
////
const AWS = require('aws-sdk')
const argv = require('yargs').argv
const {
map,
filter,
complement,
pipe,
either,
equals,
apply,
join,
propOr,
toUpper,
} = require('ramda')
////
//// Command Line Arguments
const SERVICE = argv.service || argv.s || ''
const NS = argv.namespace || argv.ns || toUpper(SERVICE)
const AS_EXPORT = Boolean(argv.asExport || argv.e)
const PROMISIFY = argv.promisify || argv.p || 'denodify'
////
//// Utility Functions
////
// capitalize ::
const capitalize =
s =>
`${s.substr(0,1).toUpperCase()}${s.substr(1)}`
// getCode ::
const getCode =
(ns, promisify) =>
methods =>
methods.map(name => `const ${ns}${capitalize(name)} = ${promisify}(${ns}.${name}, ${ns})`)
// getExport ::
const getExportCode =
(ns, promisify) =>
(methods = []) => [
`module.exports = {`, // Declare and open object literal
...methods.map(name => ` ${name}: ${promisify}(${ns}.${name}, ${ns}),`),
'}', // closed object literal
]
// notApiOrConstructor ::
const notApiOrConstructor = complement(
either(
equals('serviceIdentifier'),
either(equals('api'), equals('constructor'))
))
////
//// Main Code
////
/**
* Create Code which would promisify (denodify) an AWS service
* into either a series of declared functions or as one namespace
* that essentially has the same collection of methods as the
* service being denodified
*
* @param {string} serviceName - name of service, ie: 's3', 'sqs'.
* @param {string} [serviceNS] - namespace of service on AWS object. By
* default it assumes the `serviceName` capitalized.
* @param {string} [promisify] - name of the promisify function.
* @param {boolean} [asExport] - default false, create as object instead
* of having all individual functions.
*/
function denodeAwsServiceCode(serviceName, serviceNS = toUpper(serviceName), promisify = 'denodify', asExport = false) {
// Create the service so we can get the method names from its __proto__
const service = new AWS[serviceNS]()
// Depending on whether the code will be one namespace or many functions, we need different builder
const codeBuilder = asExport ? getExportCode : getCode
// Get the keys, filter unwanted properties, build the code
return pipe(
x => Reflect.ownKeys(x.__proto__),
filter(notApiOrConstructor),
codeBuilder(serviceName, promisify),
join('\n')
)(service)
}
////
//// If Command Line Arguments Passed, then we shall execute the function
//// to to build and output code that promisifies the AWS 'SERVICE' service
if (SERVICE && NS) {
const theCode = denodeAwsServiceCode(SERVICE, NS, PROMISIFY, AS_EXPORT)
console.log(
`/**\
\n * AWS SERVICE ${NS} AS PROMISE RETURNING FUNCTIONS\
\n */\
\n\const AWS = require('aws-sdk')
\n\
\n// denodify ::\
\nconst denodify =\
\n (fn, context = null) =>\
\n (...args) =>\
\n new Promise((resolve, reject) => {\
\n fn.call(context, ...args, (err, data) => {\
\n if (err) return reject(err)\
\n return resolve(data)\
\n })\
\n })\
\n\
\n////\
\n//// Actual AWS Service:${NS}:\
\nconst ${SERVICE} = new AWS.${NS}({/*..config..*/})\
\n\
\n////\
\n//// Denodified Versions of ${SERVICE} API methods\
\n${theCode}\
\n`
)
}
module.exports = denodeAwsServiceCode
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment