convert-lambda-to-express
Version:
Wrapper to run lambda on express. Works great for running lambdas as an express server during development but is production ready. Developed to work in conjunction with matthewkeil/full-stack-pattern cdk construct.
82 lines (81 loc) • 3.67 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.runHandler = void 0;
const util_1 = require("util");
/**
* @description handler function can return results via three methods. need to
* normalize and catch them all.
*
* 1) handler uses the deprecated methods and calls context.done(), context.fail(),
* or context.succeed(). Context was built so that context.done calls the
* resolve/reject and context.succeed and context.fail call context.done. need to
* pass resolve/reject to context object so they are available to the done function.
*
* 2) handler uses the call back function. pass in a callback function that
* uses resolve/reject from within the callback that we pass into the handler.
*
* 3) handler is an async function that returns a promise. then/catch the promise
*
*/
async function runHandler({ event, context, logger, handler, callback }) {
try {
const response = await new Promise((_resolve, _reject) => {
logger.info(`START RequestId: ${context.awsRequestId}`);
// only allow one resolution. which ever is first (callback, context.done,
// promise) wins and the other(s) is ignored
let resolved = false;
function resolve(results) {
if (!resolved) {
resolved = true;
return _resolve(results);
}
logger.error('multiple resolutions. ignoring results:');
logger.error((0, util_1.inspect)(results, false, Infinity));
}
function reject(err) {
if (!resolved) {
resolved = true;
return _reject(err);
}
logger.error('multiple resolutions. ignoring error:');
logger.error((0, util_1.inspect)(err, false, Infinity));
}
// handle case #1 from comment above. set resolve/reject on context object
// and Context class actuates them context.done/succeed/fail are called
context._resolve = resolve;
context._reject = reject;
// handle case #2 from above. build callback function that calls resolve/reject
// if callback is used by the handler.
const handlerCallback = (err, res) => {
if (err) {
return reject(err instanceof Error ? err : new Error(err));
}
resolve(res);
};
// run the handler
const voidOrPromise = handler(event, context, handlerCallback);
// handle case #3 where handler returns a promise. then/catch the promise
if (voidOrPromise) {
voidOrPromise.then(resolve).catch(reject);
}
// if voidOrPromise is nullish then handler is using callback function or context
// object for response. context timeout will watch that function doesn't hang. just
// return from promise executor here.
});
context._finalize();
context._clearTimeout();
return callback(undefined, response);
}
catch (err) {
context._finalize();
context._clearTimeout();
if (err instanceof Error) {
// errors caught from the handler function
return callback(err);
}
// something other than an error was thrown from inside the handler function
logger.error((0, util_1.inspect)(err, false, Infinity));
return callback(new Error('something other than an error was thrown from the handler'));
}
}
exports.runHandler = runHandler;
;