connect-rest
Advanced tools
Comparing version 0.0.15 to 0.0.16
@@ -6,3 +6,3 @@ /* | ||
*/ | ||
var VERSION = '0.0.15'; | ||
var VERSION = '0.0.16'; | ||
@@ -44,11 +44,11 @@ var connect = require('connect'); | ||
function addPath(key, path, action, prototypeObject, validator){ | ||
mapping[ key ].push( new Route( path, prototypeObject, validator, | ||
function addPath(key, path, action, prototypeObject, options){ | ||
mapping[ key ].push( new Route( path, prototypeObject, options, | ||
function(request, content, callback){ | ||
if(action.length == 3) { | ||
action(request, content, function(err, result){ | ||
callback(err, result); | ||
callback(err, { contentType: options.contentType || 'application/json', result : result } ); | ||
}); | ||
} else { | ||
callback(null, action(request, content)); | ||
callback(null, { contentType: options.contentType || 'application/json', result : action(request, content) } ); | ||
} | ||
@@ -65,7 +65,7 @@ }, _ | ||
var routes = _.filter( | ||
mapping[ method ], function(route){ return route.matches( | ||
var routes = _.filter( | ||
mapping[ method ], function(route){ return route.matches( | ||
null, pathname, CONTEXT, version, _, semver, false | ||
); } | ||
); | ||
); | ||
@@ -95,4 +95,4 @@ return routes.length > 0 ? _.first( _.map( routes, function(route){ return route.prototypeObject; } ) ) : 'No matching service'; | ||
var callChain = _.map( matching, function(func){ | ||
return async.apply( func, {headers: req.headers, parameters: req.query}, bodyObj ); | ||
var callChain = _.map( matching, function(func){ | ||
return async.apply( func, {headers: req.headers, parameters: req.query}, bodyObj ); | ||
} ); | ||
@@ -108,28 +108,29 @@ | ||
res.statusCode = err.statusCode || 500; | ||
res.end( 'Error occurred: ' + err ); | ||
res.end( 'Error occurred: ' + err ); | ||
} | ||
else{ | ||
res.writeHead(200, {'Content-Type': 'application/json'}); | ||
var result = _.find(results, function(returnValue){ return returnValue; }); | ||
if( result ) | ||
res.end( JSON.stringify( result ) ); | ||
var result = _.find(results, function(returnValue){ return returnValue && returnValue.result; }) || {}; | ||
console.log( '%j', result ); | ||
res.writeHead(200, {'Content-Type': result.contentType || 'application/json'}); | ||
res.end( result && result.result ? ((result.contentType == 'application/json') ? JSON.stringify( result.result ) : result.result) : '' ); | ||
} | ||
} | ||
); | ||
); | ||
} | ||
exports.head = function headRest(path, functionRef, validator){ | ||
addPath("HEAD", path, functionRef, null, validator); | ||
exports.head = function headRest(path, functionRef, options){ | ||
addPath("HEAD", path, functionRef, null, options || {} ); | ||
}; | ||
exports.get = function getRest(path, functionRef, validator){ | ||
addPath("GET", path, functionRef, null, validator); | ||
exports.get = function getRest(path, functionRef, options){ | ||
addPath("GET", path, functionRef, null, options || {} ); | ||
}; | ||
exports.post = function postRest(path, functionRef, prototypeObject, validator){ | ||
addPath("POST", path, functionRef, prototypeObject, validator); | ||
exports.post = function postRest(path, functionRef, prototypeObject, options){ | ||
addPath("POST", path, functionRef, prototypeObject, options || {} ); | ||
}; | ||
exports.put = function putRest(path, functionRef, prototypeObject, validator){ | ||
addPath("PUT", path, functionRef, prototypeObject, validator); | ||
exports.put = function putRest(path, functionRef, prototypeObject, options){ | ||
addPath("PUT", path, functionRef, prototypeObject, options || {} ); | ||
}; | ||
exports.delete = function deleteRest(path, functionRef, prototypeObject, validator){ | ||
addPath("DELETE", path, functionRef, prototypeObject, validator); | ||
exports.delete = function deleteRest(path, functionRef, prototypeObject, options){ | ||
addPath("DELETE", path, functionRef, prototypeObject, options || {} ); | ||
}; | ||
@@ -156,5 +157,5 @@ | ||
if( options.discoverPath ) | ||
addPath('GET', options.discoverPath + '/:version', discover ); | ||
addPath('GET', options.discoverPath + '/:version', discover ); | ||
if( options.protoPath ) | ||
addPath('GET', options.protoPath + '/*path', protoPather ); | ||
addPath('GET', options.protoPath + '/*path', protoPather ); | ||
API_KEYS = options.apiKeys; | ||
@@ -197,3 +198,3 @@ | ||
res.statusCode = 401; | ||
res.end( 'API_KEY is required.' ); | ||
res.end( 'API_KEY is required.' ); | ||
return; | ||
@@ -206,7 +207,7 @@ } | ||
var routes = _.filter( | ||
mapping[ req.method ], function(route){ return route.matches( | ||
var routes = _.filter( | ||
mapping[ req.method ], function(route){ return route.matches( | ||
req, pathname, CONTEXT, req.headers['accept-version'] || req.headers['x-api-version'] || '*', _, semver, true | ||
) && (!route.validator || route.validator(req, res) ); } | ||
); | ||
) && (!route.options.validator || route.options.validator(req, res) ); } | ||
); | ||
var matching = _.map( routes, function(route){ return route.action; } ); | ||
@@ -225,11 +226,11 @@ | ||
} else{ | ||
var body = ''; | ||
req.on('data', function(chunk) { | ||
body += chunk; | ||
if (body.length > LOAD_SIZE_LIMIT) { | ||
req.connection.destroy(); | ||
} | ||
}); | ||
var body = ''; | ||
req.on('data', function(chunk) { | ||
body += chunk; | ||
if (body.length > LOAD_SIZE_LIMIT) { | ||
req.connection.destroy(); | ||
} | ||
}); | ||
req.on('end', function() { | ||
req.on('end', function() { | ||
logger.debug('Body payload: ', body ); | ||
@@ -240,5 +241,5 @@ | ||
process(req, res, matching, bodyObj); | ||
} ); | ||
} | ||
}; | ||
} ); | ||
} | ||
}; | ||
}; | ||
@@ -245,0 +246,0 @@ |
@@ -26,3 +26,3 @@ var PARAMETER_M_DELIMETER = ':'; | ||
else if( this.isString ){ | ||
if (this.path == '*') | ||
if (this.path == '*') | ||
return true; | ||
@@ -33,4 +33,5 @@ | ||
if( _( _.last( ptokens ) ).startsWith( PARAMETER_O_DELIMETER ) && utokens.length == ptokens.length-1 ) | ||
utokens.push(''); | ||
for (var i=0;i<ptokens.length;i++) | ||
if( _( ptokens[i] ).startsWith( PARAMETER_O_DELIMETER ) && utokens.length <= i ) | ||
utokens.push(''); | ||
@@ -48,13 +49,13 @@ if( _( _.last( ptokens ) ).startsWith( PARAMETER_G_DELIMETER ) ){ | ||
var parameterReplacements = {}; | ||
for (var i=0;i<utokens.length;i++){ | ||
if( _( ptokens[i] ).startsWith( PARAMETER_M_DELIMETER ) ) | ||
parameterReplacements[ ptokens[i].substring( PARAMETER_M_DELIMETER.length ) ] = utokens[i]; | ||
else if( _( ptokens[i] ).startsWith( PARAMETER_G_DELIMETER ) ) | ||
parameterReplacements[ ptokens[i].substring( PARAMETER_G_DELIMETER.length ) ] = utokens[i]; | ||
else if( _( ptokens[i] ).startsWith( PARAMETER_O_DELIMETER ) ){ | ||
if( utokens[i].length>0 ) | ||
parameterReplacements[ ptokens[i].substring( PARAMETER_O_DELIMETER.length ) ] = utokens[i]; | ||
for (var t=0; t<utokens.length; t++){ | ||
if( _( ptokens[t] ).startsWith( PARAMETER_M_DELIMETER ) ) | ||
parameterReplacements[ ptokens[t].substring( PARAMETER_M_DELIMETER.length ) ] = utokens[t]; | ||
else if( _( ptokens[t] ).startsWith( PARAMETER_G_DELIMETER ) ) | ||
parameterReplacements[ ptokens[t].substring( PARAMETER_G_DELIMETER.length ) ] = utokens[t]; | ||
else if( _( ptokens[t] ).startsWith( PARAMETER_O_DELIMETER ) ){ | ||
if( utokens[t].length>0 ) | ||
parameterReplacements[ ptokens[t].substring( PARAMETER_O_DELIMETER.length ) ] = utokens[t]; | ||
} | ||
else { | ||
if( ptokens[i].toUpperCase() != utokens[i].toUpperCase() ) | ||
if( ptokens[t].toUpperCase() != utokens[t].toUpperCase() ) | ||
return false; | ||
@@ -65,3 +66,3 @@ } | ||
_.each(parameterReplacements, function(value, key, list){ | ||
req.query[ key ] = value; | ||
req.query[ key ] = value; | ||
}); | ||
@@ -72,4 +73,3 @@ | ||
else if( this.isObject ){ | ||
return (this.isSubReged ? this.path.path.test( pathname ) : this.path.path == '*' || (this.path.path.toUpperCase()==pathname.toUpperCase()) ) && | ||
matchesVersion( semver, version, this.path.version ); | ||
return (this.isSubReged ? this.path.path.test( pathname ) : this.path.path == '*' || (this.path.path.toUpperCase()==pathname.toUpperCase()) ) && matchesVersion( semver, version, this.path.version ); | ||
} | ||
@@ -76,0 +76,0 @@ return false; |
var Path = require('./path'); | ||
function Route(path, prototypeObject, validator, action, _){ | ||
this.action = action; | ||
this.prototypeObject = prototypeObject; | ||
this.validator = validator; | ||
this.paths = []; | ||
function Route(path, prototypeObject, options, action, _){ | ||
this.action = action; | ||
this.prototypeObject = prototypeObject; | ||
this.options = options || {}; | ||
this.paths = []; | ||
if( !path || !action || !_.isFunction( action ) ) | ||
throw new Error('You need to give proper parameters.'); | ||
if( !path || !action || !_.isFunction( action ) ) | ||
throw new Error('You need to give proper parameters.'); | ||
if( _.isArray( path ) ){ | ||
this.paths = _.map( path, function(element){ return new Path( element, _ ); } ); | ||
} else{ | ||
this.paths.push( new Path( path, _ ) ); | ||
} | ||
if( _.isArray( path ) ){ | ||
this.paths = _.map( path, function(element){ return new Path( element, _ ); } ); | ||
} else{ | ||
this.paths.push( new Path( path, _ ) ); | ||
} | ||
} | ||
@@ -31,11 +31,11 @@ | ||
Route.prototype.matchings = function( version, _, semver ){ | ||
var found = _.map( | ||
_.filter( this.paths, function( path ){ return path.matchings( version, _, semver); } ), function(path){ | ||
return path.path; | ||
} | ||
); | ||
var found = _.map( | ||
_.filter( this.paths, function( path ){ return path.matchings( version, _, semver); } ), function(path){ | ||
return path.path; | ||
} | ||
); | ||
return found; | ||
return found; | ||
}; | ||
module.exports = Route; |
{ | ||
"name": "connect-rest", | ||
"version": "0.0.15", | ||
"version": "0.0.16", | ||
"description": "RESTful web services middleware for Connect.", | ||
@@ -49,4 +49,4 @@ "keywords": [ | ||
"readme": "README.md", | ||
"_id": "connect-rest@0.0.15", | ||
"_from": "connect-rest@>=0.0.15" | ||
"_id": "connect-rest@0.0.16", | ||
"_from": "connect-rest@>=0.0.16" | ||
} |
@@ -28,3 +28,3 @@ [connect-rest](https://github.com/imrefazekas/connect-rest) is a middleware for [connect](http://www.senchalabs.org/connect/) for building REST APIs providing service discovery and path-based parameter mapping and "reflective" publishing and node domains as well. | ||
- [Domain support](#domain-support) | ||
- [Validation](#validation) | ||
- [Customization: Validation and Response mime-types](#customization) | ||
@@ -288,9 +288,18 @@ ## Assign | ||
## Validation | ||
## Customization | ||
When assigning routes with rest API you can pass a validation function as well, which can be used to determine if the REST function can be called in a given circumstances or should be ignored. This could mean authorization or ip address validation or other security concern. | ||
When assigning routes with rest API you can pass an object too. This object looks like this: | ||
{ | ||
contentType: '' | ||
validator: ... | ||
} | ||
The contentType defines what the given REST service will retrieve. If not given, 'application/json' will be used. | ||
The validator is a function, which can be used to determine if the REST function can be called in a given circumstances or should be ignored. This could mean authorization or ip address validation or other security concern. | ||
rest.post( [ { path: '/shake', version: '>=2.0.0' }, { path: '/twist', version: '>=2.1.1' } ], function( request, content ){ | ||
return JSON.stringify(content); | ||
}, null, function(req, res){ return _.contains(req.user.roles, "superuser"); } ); | ||
}, null, { contentType:'application/xml', validator: function(req, res){ return _.contains(req.user.roles, "superuser"); } } ); | ||
@@ -358,2 +367,5 @@ | ||
- 0.0.16: | ||
- better optional parameter handling allowing to use optional parameter chain like: /set/?depoartment/?room | ||
- rewritten assing services. instead of passing a single validator, one has to pass on optional object: { contentType: '', validator: ...} which allows one to define validator and answer return content mime-type as well. | ||
- 0.0.15 : Great changes from Joel Grenon, thank you! Standard callbacks introduced, better optional parameter handling and respecting error status code if exists | ||
@@ -360,0 +372,0 @@ - 0.0.14 : Adding grunt project files |
@@ -92,3 +92,3 @@ var opt = { | ||
var voptions = _.clone( opt ); | ||
voptions.path = '/api/make'; | ||
voptions.path = '/api/make?api_key=849b7648-14b8-4154-9ef2-8d1dc4c2b7e9'; | ||
voptions.method = 'POST'; | ||
@@ -124,2 +124,24 @@ voptions.headers['accept-version'] = '1.1'; | ||
function testCall8a(http, _, callback){ | ||
var voptions = _.clone( opt ); | ||
voptions.method = 'GET'; | ||
voptions.path = '/api/set?api_key=849b7648-14b8-4154-9ef2-8d1dc4c2b7e9'; | ||
generalCall( http, voptions, callback ); | ||
} | ||
function testCall8b(http, _, callback){ | ||
var voptions = _.clone( opt ); | ||
voptions.method = 'GET'; | ||
voptions.path = '/api/set/abraka?api_key=849b7648-14b8-4154-9ef2-8d1dc4c2b7e9'; | ||
generalCall( http, voptions, callback ); | ||
} | ||
function testCall8c(http, _, callback){ | ||
var voptions = _.clone( opt ); | ||
voptions.method = 'GET'; | ||
voptions.path = '/api/set/abraka/dabra?api_key=849b7648-14b8-4154-9ef2-8d1dc4c2b7e9'; | ||
generalCall( http, voptions, callback ); | ||
} | ||
exports.testCall1 = testCall1; | ||
@@ -133,1 +155,5 @@ exports.testCall2 = testCall2; | ||
exports.testCall7 = testCall7; | ||
exports.testCall8a = testCall8a; | ||
exports.testCall8b = testCall8b; | ||
exports.testCall8c = testCall8c; |
@@ -14,20 +14,23 @@ function buildUpRestAPI( rest, _ ){ | ||
console.log( 'Received:' + JSON.stringify( request ) + ' ' + JSON.stringify(content) ); | ||
callback(null, 'ok'); | ||
return callback(null, 'ok'); | ||
}); | ||
rest.get('/inquire/*book', function( request, content, callback ){ | ||
console.log( 'Received:' + JSON.stringify( request ) + ' ' + JSON.stringify(content) ); | ||
callback(null, 'ok'); | ||
return callback(null, 'ok'); | ||
}); | ||
rest.get( '/set/?rid/?facet', function( request, content, callback ){ | ||
console.log( 'Received:' + JSON.stringify( request ) + ' ' + JSON.stringify(content) ); | ||
return callback(null, 'ok'); | ||
}); | ||
rest.post( { path: '/make', version: '>=1.0.0' }, function( request, content, callback ){ | ||
console.log( 'Received:' + JSON.stringify( request ) + ' ' + JSON.stringify(content) ); | ||
callback(null, 'ok'); | ||
return callback(null, 'ok'); | ||
}); | ||
rest.post( [ '/act', '/do' ], function( request, content, callback ){ | ||
console.log( 'Received:' + JSON.stringify( request ) + ' ' + JSON.stringify(content) ); | ||
callback( null, 'ok' ); | ||
return callback( null, 'ok' ); | ||
}); | ||
rest.post( [ { path: '/shake', version: '>=2.0.0' }, { path: '/twist', version: '>=2.1.1' } ], function( request, content, callback ){ | ||
console.log( 'Received:' + JSON.stringify( request ) + ' ' + JSON.stringify(content) ); | ||
//throw new Error('Shake error...'); | ||
callback(null, 'ok'); | ||
return callback(null, 'ok'); | ||
}, {'title': 'Alice in Wonderland'} ); | ||
@@ -34,0 +37,0 @@ } |
@@ -60,10 +60,13 @@ var rest = require('../lib/connect-rest'); | ||
async.parallel([ | ||
async.apply( caller.testCall1, http, _ ), | ||
async.apply( caller.testCall2, http, _ ), | ||
async.apply( caller.testCall3a, http, _ ), | ||
async.apply( caller.testCall3b, http, _ ), | ||
async.apply( caller.testCall4, http, _ ), | ||
async.apply( caller.testCall5, http, _ ), | ||
async.apply( caller.testCall6, http, _ ), | ||
async.apply( caller.testCall7, http, _ ) | ||
// async.apply( caller.testCall1, http, _ ), | ||
// async.apply( caller.testCall2, http, _ ), | ||
// async.apply( caller.testCall3a, http, _ ), | ||
// async.apply( caller.testCall3b, http, _ ), | ||
// async.apply( caller.testCall4, http, _ ), | ||
// async.apply( caller.testCall5, http, _ ), | ||
// async.apply( caller.testCall6, http, _ ), | ||
// async.apply( caller.testCall7, http, _ ), | ||
async.apply( caller.testCall8a, http, _ ), | ||
async.apply( caller.testCall8b, http, _ ), | ||
async.apply( caller.testCall8c, http, _ ) | ||
], function(err, results){ | ||
@@ -70,0 +73,0 @@ console.log('Tests finished.'); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
40555
535
381