🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

uservit

Package Overview
Dependencies
Maintainers
1
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

uservit - npm Package Compare versions

Comparing version
0.0.3
to
0.0.4
+151
test/with_proxy.js
/*
* @author Marcelo Gornstein <marcelog@gmail.com>
* @license Apache-2.0
* @copyright 2017 Marcelo Gornstein
*/
'use strict';
var assert = require('assert');
var promise = require('promise');
var chai = require('chai');
var expect = chai.expect;
var chaiAsPromised = require('chai-as-promised');
var m = require('../src/index');
chai.use(chaiAsPromised);
chai.should();
describe('generic handler with proxy', function () {
describe('basic features', function () {
it('lowercases header names', function () {
var callback = function (err, result) {
assertSuccess(err, result, {}, {});
};
return expect(
m.handleProxy(
{headers: {'HEADER': 'value'}},
{context: true},
callback,
function (event, context) {
assert.equal(event.headers['header'], 'value');
assert.equal(event.headers['HEADER'], undefined);
return {};
}
)
).to.be.eventually.fulfilled.and.equal(true);
});
it('handles requests', function () {
var callback = function (err, result) {
assertSuccess(err, result, {}, {});
};
return assertHandler(handler0, callback);
});
it('returns client errors', function () {
var callback = function (err, result) {
assertClientError(err, result, {}, 'some_client_error');
};
return assertHandler(handler2, callback);
});
it('returns success with body', function () {
var callback = function (err, result) {
assertSuccess(err, result, {}, {
result: 'some_result'
});
};
return assertHandler(handler1, callback);
});
it('returns custom status code, body, and headers', function () {
var callback = function (err, result) {
assertResult(err, result, 999, {
'custom-header': 'custom-value'
}, {
result: {whatever: 'value'}
});
};
return assertHandler(handler3, callback);
});
it('handles unexpected errors', function () {
var callback = function (err, result) {
assertInternalError(err, result);
};
return assertHandler(handler4, callback);
});
});
});
////////////////////////////////////////////////////////////////////////////////
// Handler functions for tests.
////////////////////////////////////////////////////////////////////////////////
function handler0 (event, context) {
assert.deepEqual(event, {event: true, headers: {}});
assert.deepEqual(context, {context: true});
return true;
};
function handler1 (event, context) {
return {
body: {
result: 'some_result'
}
};
};
function handler2 (event, context) {
return promise.reject({
clientError: true,
message: 'some_client_error'
});
};
function handler3 (event, context) {
return promise.resolve({
statusCode: 999,
headers: {
'custom-header': 'custom-value'
},
body: {
whatever: 'value'
}
});
};
function handler4 (event, context) {
throw new Error('oops');
};
////////////////////////////////////////////////////////////////////////////////
// Helper functions for assertions.
////////////////////////////////////////////////////////////////////////////////
function assertHandler(fn, callback) {
return expect(
m.handleProxy({event: true}, {context: true}, callback, fn)
).to.be.eventually.fulfilled.and.equal(true);
}
function assertInternalError(err, result) {
return assertResult(err, result, 500, {}, {message: 'server_error'});
};
function assertSuccess(err, result, headers, body) {
return assertResult(err, result, 200, headers, {result: body});
};
function assertClientError(err, result, headers, msg) {
return assertResult(err, result, 400, headers, {message: msg});
};
function assertResult(err, result, statusCode, headers, body) {
headers['Access-Control-Allow-Origin'] = '*';
headers['Access-Control-Allow-Credentials'] = true;
assert.equal(err, undefined);
assert.deepEqual(result, {
statusCode: statusCode,
headers: headers,
body: JSON.stringify(body)
});
return true;
}
/*
* @author Marcelo Gornstein <marcelog@gmail.com>
* @license Apache-2.0
* @copyright 2017 Marcelo Gornstein
*/
'use strict';
var assert = require('assert');
var promise = require('promise');
var chai = require('chai');
var expect = chai.expect;
var chaiAsPromised = require('chai-as-promised');
var m = require('../src/index');
chai.use(chaiAsPromised);
chai.should();
describe('generic handler without proxy', function () {
describe('basic features', function () {
it('handles requests', function () {
var callback = function (err, result) {
assertSuccess(err, result, {}, {});
};
return assertHandler(handler0, callback);
});
it('returns client errors', function () {
var callback = function (err, result) {
assertClientError(err, result, {}, ['some_error']);
};
return assertHandler(handler2, callback);
});
it('returns success with body', function () {
var callback = function (err, result) {
assertSuccess(err, result, {}, {
result: 'some_result'
});
};
return assertHandler(handler1, callback);
});
it('returns custom body, and headers', function () {
var callback = function (err, result) {
assertResult(
err,
result,
undefined,
{
headers: {'custom-header': 'custom-value'},
body: {whatever: 'value'}
}
);
};
return assertHandler(handler3, callback);
});
it('handles unexpected errors', function () {
var callback = function (err, result) {
assertInternalError(err, result);
};
return assertHandler(handler4, callback);
});
});
});
////////////////////////////////////////////////////////////////////////////////
// Handler functions for tests.
////////////////////////////////////////////////////////////////////////////////
function handler0 (event, context) {
assert.deepEqual(event, {event: true, body: {}, headers: {}});
assert.deepEqual(context, {context: true});
return {body: {}};
};
function handler1 (event, context) {
return {
body: {
result: 'some_result'
}
};
};
function handler2 (event, context) {
return promise.reject({
message: 'client_error',
errors: ['some_error']
});
};
function handler3 (event, context) {
return promise.resolve({
headers: {
'custom-header': 'custom-value'
},
body: {
whatever: 'value'
}
});
};
function handler4 (event, context) {
throw new Error('oops');
};
////////////////////////////////////////////////////////////////////////////////
// Helper functions for assertions.
////////////////////////////////////////////////////////////////////////////////
function assertHandler(fn, callback) {
return expect(
m.handle(
{event: true, body: JSON.stringify({}), headers: {}},
{context: true},
callback,
fn
)
).to.be.eventually.fulfilled.and.equal(true);
}
function assertInternalError(err, result) {
return assertResult(
err,
result,
JSON.stringify({
body: {message: 'server_error', errors: []},
headers: {}
}),
undefined
);
};
function assertSuccess(err, result, headers, body) {
return assertResult(
err, result, undefined, {body: body, headers: headers}
);
};
function assertClientError(err, result, headers, errors) {
return assertResult(
err,
result,
JSON.stringify({
body: {message: 'client_error', errors: errors},
headers: headers
}),
undefined
);
};
function assertResult(err, result, expectedErr, expectedResult) {
assert.equal(err, expectedErr);
assert.deepEqual(result, expectedResult);
return true;
}
+1
-1
{
"name": "uservit",
"description": "Small, thin layer, that serves your serverless microservices generically",
"version": "0.0.3",
"version": "0.0.4",
"keywords": ["serverless", "promise", "microservice"],

@@ -6,0 +6,0 @@ "homepage": "https://github.com/switchpaas/uservit",

+156
-2

@@ -39,2 +39,5 @@ [![License](http://img.shields.io/badge/license-APACHE2-blue.svg)](http://img.shields.io/badge/license-APACHE2-blue.svg)

----
### Lambda Integration (With Proxy)
Let's say you want to handle a request with the function `users.get` (that would

@@ -50,3 +53,3 @@ be the function `get` inside the module `users`), you would write your

exports.hello = function (event, context, callback) {
return uservit.handle(event, context, callback, users.get);
return uservit.handleProxy(event, context, callback, users.get);
};

@@ -124,6 +127,157 @@ ```

{
"message": "internal_error"
"message": "server_error"
}
```
----
### Lambda (No Proxy integration)
To leverage the available features when using the proxy feature, you have to
add a [mapping template for the request](docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html).
This is based on the one available at [https://kennbrodhagen.net/2015/12/06/how-to-create-a-request-object-for-your-lambda-event-from-api-gateway/](https://kennbrodhagen.net/2015/12/06/how-to-create-a-request-object-for-your-lambda-event-from-api-gateway/).
## Request template sample
```
{
"body" : "$util.escapeJavaScript($input.json('$'))",
"headers": {
#foreach($header in $input.params().header.keySet())
"$header.toLowerCase()": "$util.escapeJavaScript($input.params().header.get($header))" #if($foreach.hasNext),#end
#end
},
"method": "$context.httpMethod",
"params": {
#foreach($param in $input.params().path.keySet())
"$param.toLowerCase()": "$util.escapeJavaScript($input.params().path.get($param))" #if($foreach.hasNext),#end
#end
},
"query": {
#foreach($queryParam in $input.params().querystring.keySet())
"$queryParam.toLowerCase()": "$util.escapeJavaScript($input.params().querystring.get($queryParam))" #if($foreach.hasNext),#end
#end
}
}
```
## Response template sample
For the 200 status code we need to return the contents of the `body` field as
JSON, so this template mapping is required:
```
$input.json('$.body')
```
For errors, this generic template will be used:
```
#set ($errorMessageObj = $util.parseJson($input.path('$.errorMessage')))
{"message": "$errorMessageObj.body.message","errors": [#foreach( $e in $errorMessageObj.body.errors )"$e"#if($foreach.hasNext),#end#end]}
```
And to return custom status codes the following mappings should be added too:
```
400: '.*"message":"client_error".*'
401: '.*"message":"unauthorized".*'
402: '.*"message":"payment_required".*'
403: '.*"message":"forbidden".*'
404: '.*"message":"not_found".*'
429: '.*"message":"throttled".*'
500: '((.*Process exited before completing request.*)|(.*server_error.*))'
```
Let's say you want to handle a request with the function `users.get` (that would
be the function `get` inside the module `users`), you would write your
ServerLess service handler like this:
```js
'use strict';
var uservit = require('uservit');
var users = require('users');
exports.hello = function (event, context, callback) {
return uservit.handle(event, context, callback, users.get);
};
```
That's it! In your service (the function `users.get`) you can then do:
```js
'use strict';
var promise = require('promise');
exports.get = function (event, context) {
return promise.resolve().
then(function () {
//
}).
then(function () {
//
}).
catch(function (err) {
// ...
});
};
```
### Returning successful responses
Just return a `body` field with what you want, like:
```js
{
body: {
success: true
}
}
```
And the HTTP client will see a payload like:
```json
{
"result": {
"success": true
}
}
```
### Returning custom HTTP status codes and Headers
```js
{
message: 'payment_required',
headers: {
'custom-header': 'a value'
}
}
```
The pattern for `402` will match and the right HTTP status code will be sent. To
return the custom header, you will need to map the header in the response like
`integration.response.body.headers.custom-header`.
### Returning client errors
You can fail your promise and return something like this:
```js
return promise.reject({
message: 'client_error',
errors: ['missing_parameter']
});
```
And the HTTP client will see an HTTP status code of 400 with a payload like:
```json
{
"message": "client_error",
errors: ['missing_parameter']
}
```
### Unexpected errors
When something in your code fails, your promises will also be rejected and your
client will see an HTTP status code 500 with a payload like:
```json
{
"message": "server_error"
}
```
----
# Developers

@@ -130,0 +284,0 @@ This project uses standard [npm scripts](https://docs.npmjs.com/cli/run-script). Current tasks include:

'use strict';
var promise = require('promise');
exports.handle = function (event, context, callback, fn) {
exports.handleProxy = function (event, context, callback, fn) {
var withError = false;

@@ -32,3 +32,3 @@ var ret = {

ret.statusCode = 500;
ret.body = {message: 'internal_error'};
ret.body = {message: 'server_error'};
if (result.clientError) {

@@ -52,1 +52,36 @@ ret.statusCode = 400;

};
exports.handle = function (event, context, callback, fn) {
event.body = JSON.parse(event.body);
return promise.resolve().then(function () {
return fn(event, context);
}).catch(function (error) {
var ret = {body: {}, headers: {}};
switch (error.message) {
case 'client_error':
ret.body.message = 'client_error';
ret.body.errors = error.errors;
break;
default:
ret.body.message = 'server_error';
ret.body.errors = []; // This is not needed, but without it, the mapping
// reponse for 500 wont match :\
break;
}
return ret;
}).then(function (result) {
var ret = {
body: result.body,
headers: result.headers
};
if (!ret.headers) {
ret.headers = {};
}
if (Array.isArray(result.body.errors)) {
callback(JSON.stringify(ret), undefined);
return true;
}
callback(undefined, ret);
return true;
});
};
/*
* @author Marcelo Gornstein <marcelog@gmail.com>
* @license Apache-2.0
* @copyright 2017 Marcelo Gornstein
*/
'use strict';
var assert = require('assert');
var promise = require('promise');
var chai = require('chai');
var expect = chai.expect;
var chaiAsPromised = require('chai-as-promised');
var m = require('../src/index');
chai.use(chaiAsPromised);
chai.should();
describe('generic handler', function () {
describe('basic features', function () {
it('lowercases header names', function () {
var callback = function (err, result) {
assertSuccess(err, result, {}, {});
};
return expect(
m.handle(
{headers: {'HEADER': 'value'}},
{context: true},
callback,
function (event, context) {
assert.equal(event.headers['header'], 'value');
assert.equal(event.headers['HEADER'], undefined);
return {};
}
)
).to.be.eventually.fulfilled.and.equal(true);
});
it('handles requests', function () {
var callback = function (err, result) {
assertSuccess(err, result, {}, {});
};
return assertHandler(handler0, callback);
});
it('returns client errors', function () {
var callback = function (err, result) {
assertClientError(err, result, {}, 'some_client_error');
};
return assertHandler(handler2, callback);
});
it('returns success with body', function () {
var callback = function (err, result) {
assertSuccess(err, result, {}, {
result: 'some_result'
});
};
return assertHandler(handler1, callback);
});
it('returns custom status code, body, and headers', function () {
var callback = function (err, result) {
assertResult(err, result, 999, {
'custom-header': 'custom-value'
}, {
result: {whatever: 'value'}
});
};
return assertHandler(handler3, callback);
});
it('handles unexpected errors', function () {
var callback = function (err, result) {
assertInternalError(err, result);
};
return assertHandler(handler4, callback);
});
});
});
////////////////////////////////////////////////////////////////////////////////
// Handler functions for tests.
////////////////////////////////////////////////////////////////////////////////
function handler0 (event, context) {
assert.deepEqual(event, {event: true, headers: {}});
assert.deepEqual(context, {context: true});
return true;
};
function handler1 (event, context) {
return {
body: {
result: 'some_result'
}
};
};
function handler2 (event, context) {
return promise.reject({
clientError: true,
message: 'some_client_error'
});
};
function handler3 (event, context) {
return promise.resolve({
statusCode: 999,
headers: {
'custom-header': 'custom-value'
},
body: {
whatever: 'value'
}
});
};
function handler4 (event, context) {
throw new Error('oops');
};
////////////////////////////////////////////////////////////////////////////////
// Helper functions for assertions.
////////////////////////////////////////////////////////////////////////////////
function assertHandler(fn, callback) {
return expect(
m.handle({event: true}, {context: true}, callback, fn)
).to.be.eventually.fulfilled.and.equal(true);
}
function assertInternalError(err, result) {
return assertResult(err, result, 500, {}, {message: 'internal_error'});
};
function assertSuccess(err, result, headers, body) {
return assertResult(err, result, 200, headers, {result: body});
};
function assertClientError(err, result, headers, msg) {
return assertResult(err, result, 400, headers, {message: msg});
};
function assertResult(err, result, statusCode, headers, body) {
headers['Access-Control-Allow-Origin'] = '*';
headers['Access-Control-Allow-Credentials'] = true;
assert.equal(err, undefined);
assert.deepEqual(result, {
statusCode: statusCode,
headers: headers,
body: JSON.stringify(body)
});
return true;
}