Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for wrapping http services #19

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![Build Status](https://travis-ci.org/nordcloud/lambda-wrapper.svg?branch=master)](https://travis-ci.org/nordcloud/lambda-wrapper)

Wrapper for running lambda modules locally or from AWS during development
Wrapper for running lambda modules locally, remotely via http or from AWS during development

## Use

Expand All @@ -11,6 +11,10 @@ Wrapper for running lambda modules locally or from AWS during development
// Loads the module in myModule/mymod.js
var lambdaFunc = require('myModule/mymod.js');
var lambda = require('lambda-wrapper').wrap(lambdaFunc);

### Initializing a lambda wrapped by an http server

var lambda = require('lambda-wrapper').wrap('https://my-lambda-service/');

### Initializing a lambda in AWS

Expand All @@ -33,6 +37,11 @@ If you want to pass a custom context to the Lambda module (only when running loc

lambda.runHandler(event, customContext, callback)

Accessing a lambda running as a remote service can be useful when calling lambdas that sit in different projects.
E.g. Node Project A invokes Lambda in Project B.
Using e.g. [serverless-offline-direct-lambda](https://github.com/dankelleher/serverless-offline-direct-lambda),
the lambda can be wrapped in an http server and called from project A.

Documentation for valid propreties in the Lambda context object are documented here http://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-context.html

Exceptions from within the module will be returned as errors via the callback / promise.
Expand Down
15 changes: 15 additions & 0 deletions httpRunner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
var fetch = require('node-fetch');

const payload = data => JSON.parse(data.Payload);

function runHttp(event, url, cb) {
fetch(url, {
method: 'POST',
body: JSON.stringify(event),
headers: { 'Content-Type': 'application/json' }})
.then(res => res.json())
.then(json => cb(null, payload(json)))
.catch(cb);
}

module.exports = runHttp;
76 changes: 52 additions & 24 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

const AWS = require('aws-sdk');

const httpRunner = require('./httpRunner');

// Wrapper class for AWS Lambda
class Wrapped {
constructor(mod, opts) {
Expand All @@ -15,6 +17,40 @@ class Wrapped {
}
}

runDirect(event, context, cb) {
this.handler(event, context, cb);
}

runRemote(event, cb) {
if (this.lambdaModule.region) {
AWS.config.update({
region: this.lambdaModule.region
});
}

const lambda = new AWS.Lambda();
const params = {
FunctionName: this.lambdaModule.lambdaFunction,
InvocationType: 'RequestResponse',
LogType: 'None',
Payload: JSON.stringify(event)
};

lambda.invoke(params, (err, data) => {
if (err) {
return cb(err);
}
if (data.FunctionError) {
return cb(Object.assign(new Error(JSON.parse(data.Payload).errorMessage), data));
}
return cb(null, JSON.parse(data.Payload));
});
}

runHttp(event, cb) {
httpRunner(event, this.lambdaModule, cb);
}

runHandler(event, customContext, cb) {
return new Promise((resolve, reject) => {

Expand All @@ -37,31 +73,15 @@ class Wrapped {

try {
if (this.handler) {
this.handler(event, lambdaContext, callback);
} else {
if (this.lambdaModule.region) {
AWS.config.update({
region: this.lambdaModule.region
});
if (isFunction(this.handler)) {
this.runDirect(event, lambdaContext, callback);
} else {
reject('Handler is not a function');
}

const lambda = new AWS.Lambda();
const params = {
FunctionName: this.lambdaModule.lambdaFunction,
InvocationType: 'RequestResponse',
LogType: 'None',
Payload: JSON.stringify(event)
};

lambda.invoke(params, (err, data) => {
if (err) {
return callback(err);
}
if (data.FunctionError) {
return callback(Object.assign(new Error(JSON.parse(data.Payload).errorMessage), data));
}
return callback(null, JSON.parse(data.Payload));
});
} else if (isString(this.lambdaModule)) {
this.runHttp(event, callback);
} else {
this.runRemote(event, callback);
}
} catch (ex) {
return callback(ex);
Expand All @@ -81,6 +101,14 @@ class Wrapped {
}
}

function isFunction(functionToCheck) {
return functionToCheck && {}.toString.call(functionToCheck) === '[object Function]';
}

function isString(value) {
return typeof value === 'string';
}

// Wrapper factory

const wrap = (mod, options) => new Wrapped(mod, options);
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"mocha": "2.4.5"
},
"dependencies": {
"aws-sdk": "^2.4.0"
"aws-sdk": "^2.4.0",
"node-fetch": "^2.0.0"
}
}
28 changes: 28 additions & 0 deletions test/test-wrapper.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
'use strict';
const http = require('http');

const wrapper = require('../index.js');
const httpRunner = require('../httpRunner.js');
const expect = require('chai').expect;

const testMod1 = {
Expand Down Expand Up @@ -225,6 +227,32 @@ describe('lambda-wrapper local', () => {
});
});

describe('httpRunner', () => {
it('can make an http call', function (done) {
const port = process.env.PORT || 3101;
const url = 'http://localhost:' + port;

const w = wrapper.wrap(url);

const requestHandler = (request, response) => {
response.end(JSON.stringify({
Payload:
JSON.stringify({ test: 'success' })
}))
};

const server = http.createServer(requestHandler);

server.listen(port);

w.run({ test: 'cbsuccess' }, (error, response) => {
expect(response.test).to.be.equal('success');

server.close(done);
})
});
});

if (process.env.RUN_LIVE) {
describe('lambda-wrapper live', () => {
it('can call lambda functions deployed in AWS - callback', (done) => {
Expand Down