express-api-routes
Advanced tools
Comparing version 1.1.2 to 1.1.3
133
index.js
@@ -1,27 +0,27 @@ | ||
'use strict'; | ||
'use strict' | ||
const express = require('express'); | ||
const app = express(); | ||
const Router = express.Router(); | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const Controllers = require('./lib/Controllers'); | ||
const Policies = require('./lib/Policies'); | ||
const Routes = require('./lib/Routes'); | ||
const nodeWatch = require('node-watch'); | ||
const winston = require('winston') | ||
const express = require('express') | ||
const app = express() | ||
const Router = express.Router() | ||
const path = require('path') | ||
const Controllers = require('./lib/Controllers') | ||
const Policies = require('./lib/Policies') | ||
const Routes = require('./lib/Routes') | ||
class ExpressApiRoutes { | ||
constructor(setup = {}) { | ||
this.config = {} | ||
this.config.rootDir = setup.rootDir || path.parse(process.mainModule.filename).dir; | ||
this.config.baseRoute = setup.baseRoute || '/'; | ||
this.config.controllersDir = setup.controllers || path.join(this.config.rootDir,"controllers"); | ||
this.config.controllers = {}; | ||
this.config.policiesDir = setup.policies || path.join(this.config.rootDir,"policies"); | ||
this.config.policies = {}; | ||
this.config.routes = setup.routes || {}; | ||
this.config.app = setup.app || app; | ||
this.config.router = Router; | ||
this.config.global = setup.global || false; | ||
constructor (setup = {}) { | ||
this.config = { | ||
logger: this.ensureLogger(setup.logger) | ||
} | ||
this.config.rootDir = setup.rootDir || path.parse(process.mainModule.filename).dir | ||
this.config.baseRoute = setup.baseRoute || '/' | ||
this.config.controllersDir = setup.controllers || path.join(this.config.rootDir, 'controllers') | ||
this.config.controllers = {} | ||
this.config.policiesDir = setup.policies || path.join(this.config.rootDir, 'policies') | ||
this.config.policies = {} | ||
this.config.routes = setup.routes || {} | ||
this.config.app = setup.app || app | ||
this.config.router = Router | ||
this.config.global = setup.global || false | ||
this.config.routeMap = [] // for debug/loggging only | ||
@@ -32,74 +32,43 @@ | ||
this.watchForFileChange() | ||
return this.config.app | ||
} | ||
return this.config.app; | ||
ensureLogger (logger) { | ||
if (logger && (logger instanceof winston.Logger)) { | ||
return logger | ||
} | ||
return new (winston.Logger)({ | ||
transports: [ | ||
new (winston.transports.Console)({ | ||
color: true, | ||
level: 'silly' | ||
}) | ||
] | ||
}) | ||
} | ||
doWork() { | ||
doWork () { | ||
this.config.routeMap = [] // reset route map | ||
// setup controllers | ||
new Controllers(this.config); | ||
new Controllers(this.config) // eslint-disable-line | ||
// setip policies | ||
new Policies(this.config); | ||
new Policies(this.config) // eslint-disable-line | ||
// finalize all routing | ||
new Routes(this.config); | ||
new Routes(this.config) // eslint-disable-line | ||
// make the express app use the Router | ||
this.config.app.use(this.config.baseRoute, this.config.router); | ||
this.config.app.use(this.config.baseRoute, this.config.router) | ||
// console.log(`Controllers:`, this.config.controllers); | ||
// console.log(`Policies:`, this.config.policies); | ||
// console.log(`Routes:`, this.config.routes); | ||
console.log('\n'); | ||
console.log('+++ ExpressApiRoutes'); | ||
this.config.routeMap.forEach(r=>{ console.log(` ${this.config.baseRoute}${r}`) }) | ||
console.log('\n'); | ||
// console.log(`Controllers:`, this.config.controllers) | ||
// console.log(`Policies:`, this.config.policies) | ||
// console.log(`Routes:`, this.config.routes) | ||
this.config.logger.info('routes setup') | ||
this.config.routeMap.forEach(r => { | ||
this.config.logger.info(` ${r}`) | ||
}) | ||
} | ||
watchForFileChange() { | ||
if (process.NODE_ENV === 'production') { return } | ||
const self = this; | ||
let filesToWatch = [] | ||
if (this.config.policiesDir) { | ||
filesToWatch.push(this.config.policiesDir) | ||
} | ||
if (this.config.controllersDir) { | ||
filesToWatch.push(this.config.controllersDir) | ||
} | ||
if (this.config.routes) { | ||
// attempt a default route dir/file | ||
let routesStat | ||
try { | ||
routesStat = fs.statSync(path.join(this.config.rootDir,'config','routes.js')) | ||
} catch(e) {} | ||
if (routesStat && routesStat.isDirectory()) { | ||
filesToWatch.push(path.join(this.config.rootDir,'config','routes.js')) | ||
} | ||
} | ||
nodeWatch(filesToWatch, function(filename) { | ||
console.log('+++ ExpressApiRoutes - file has changed:'); | ||
console.log(` ${filename}`); | ||
console.log('+++ Reloading routes...'); | ||
self.doWork(); | ||
}); | ||
} | ||
} | ||
// const ourApp = new ExpressApiRoutes({ | ||
// root: __dirname, // defaults to process.mainFile.filename dir | ||
// baseRoute: '/api/v1', // defaults to '/' | ||
// controllers: __dirname + "/test/controllers", // default @param absolute | ||
// policies: __dirname + "/test/policies", // default @param absolute | ||
// routes: require('./test/config/routes'), // default | ||
// app: app, // creates an express app if none provided | ||
// // global: myGlobalAppObj // none specified by default | ||
// }); | ||
// app.listen(3002) | ||
module.exports = ExpressApiRoutes; | ||
module.exports = ExpressApiRoutes |
@@ -1,39 +0,39 @@ | ||
'use strict'; | ||
'use strict' | ||
/** | ||
/* | ||
* lib/Controllers.js | ||
* This module provides helper methods for actions with/on/for controllers. | ||
* It's constructor sets up the controllers and reads the controller dir | ||
* This module provides helper methods for actions with/on/for controllers. | ||
* It's constructor sets up the controllers and reads the controller dir | ||
*/ | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const fs = require('fs') | ||
const path = require('path') | ||
module.exports = class Controllers { | ||
constructor(config) { | ||
// check controllers directory exists | ||
var controllersDir; | ||
module.exports = | ||
class Controllers { | ||
constructor (config) { | ||
// check controllers directory exists | ||
var controllersDir | ||
try { | ||
controllersDir = fs.statSync(config.controllersDir); | ||
} catch(e) { controllersDir = false; } | ||
if (!controllersDir || !controllersDir.isDirectory()) { | ||
console.error(`+++ ExpressApiRoutes - Error controllersDir does not exist: | ||
${config.controllersDir} `); | ||
process.exit(); | ||
} | ||
try { | ||
controllersDir = fs.statSync(config.controllersDir) | ||
} catch (e) { controllersDir = false } | ||
// read controller dir files | ||
fs.readdirSync(config.controllersDir).forEach((fileName) => { | ||
if (!/(.js)$/.test(fileName) ) { return null; } | ||
const fileNamespace = fileName.toLowerCase().replace('.js',''); | ||
if (!controllersDir || !controllersDir.isDirectory()) { | ||
config.logger.warn(`Error controllersDir does not exist: | ||
${config.controllersDir} `) | ||
process.exit() | ||
} | ||
config.controllers[fileNamespace] = require(path.join(config.controllersDir,fileName)); | ||
}); | ||
// read controller dir files | ||
fs.readdirSync(config.controllersDir).forEach((fileName) => { | ||
if (!/(.js)$/.test(fileName)) { | ||
return null | ||
} | ||
} | ||
const fileNamespace = fileName.toLowerCase().replace('.js', '') | ||
makeRoutes() { | ||
} | ||
config.controllers[fileNamespace] = require(path.join(config.controllersDir, fileName)) | ||
}) | ||
} | ||
} |
@@ -1,36 +0,36 @@ | ||
'use strict'; | ||
'use strict' | ||
/** | ||
* lib/Policies.js | ||
* This module provides helper methods for actions with/on/for policies. | ||
* It's constructor sets up the policies and reads the policies dir | ||
* This module provides helper methods for actions with/on/for policies. | ||
* It's constructor sets up the policies and reads the policies dir | ||
*/ | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const fs = require('fs') | ||
const path = require('path') | ||
module.exports = class Policies { | ||
constructor(parent) { | ||
// check policies directory exists | ||
var policiesDir; | ||
module.exports = | ||
class Policies { | ||
constructor (config) { | ||
// check policies directory exists | ||
var policiesDir | ||
try { | ||
policiesDir = fs.statSync(parent.policiesDir); | ||
} catch(e) { policiesDir = false; } | ||
if (!policiesDir || !policiesDir.isDirectory()) { | ||
console.error(`+++ ExpressApiRoutes - Error policiesDir does not exist: | ||
${parent.policiesDir} `); | ||
process.exit(); | ||
} | ||
try { | ||
policiesDir = fs.statSync(config.policiesDir) | ||
} catch (e) { policiesDir = false } | ||
if (!policiesDir || !policiesDir.isDirectory()) { | ||
config.logger.warn(`Error policiesDir does not exist: | ||
${config.policiesDir} `) | ||
process.exit() | ||
} | ||
// read controller dir files | ||
fs.readdirSync(parent.policiesDir).forEach((fileName) => { | ||
if (!/(.js)$/.test(fileName) ) { return null; } | ||
const fileNamespace = fileName.toLowerCase().replace('.js',''); | ||
// read controller dir files | ||
fs.readdirSync(config.policiesDir).forEach((fileName) => { | ||
if (!/(.js)$/.test(fileName)) { return null } | ||
const fileNamespace = fileName.toLowerCase().replace('.js', '') | ||
parent.policies[fileNamespace] = require(path.join(parent.policiesDir,fileName)); | ||
}); | ||
config.policies[fileNamespace] = require(path.join(config.policiesDir, fileName)) | ||
}) | ||
} | ||
} | ||
} |
@@ -1,135 +0,128 @@ | ||
'use strict'; | ||
'use strict' | ||
/** | ||
* lib/Routes.js | ||
* This module provides helper methods for actions with/on/for routes. | ||
* It's constructor sets up the routes and reads the controller dir | ||
* This module provides helper methods for actions with/on/for routes. | ||
* It's constructor sets up the routes and reads the controller dir | ||
*/ | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
module.exports = | ||
class Routes { | ||
constructor (config) { | ||
this.config = config | ||
module.exports = class Routes { | ||
constructor(config = {}) { | ||
this.config = config | ||
this.makeConfigRoutes() | ||
this.makeControllerRoutes() | ||
} | ||
this.makeConfigRoutes() | ||
this.makeControllerRoutes() | ||
} | ||
makeConfigRoutes () { | ||
const routes = this.config.routes | ||
// iterate the routes config and make sure all controller/method & policies exist | ||
for (var path in routes) { | ||
if (!this.config.controllers[routes[path].controller]) { | ||
this.config.logger.warn(new Error(`Route ${path} controller "${routes[path].controller}" doesn't exist`)) | ||
process.exit() | ||
} else if (!this.config.controllers[routes[path].controller][routes[path].method]) { | ||
this.config.logger.warn(new Error(`Route ${path} controller method "${routes[path].controller}.${routes[path].method}" doesn't exist`)) | ||
process.exit() | ||
} | ||
makeConfigRoutes() { | ||
const routes = this.config.routes | ||
// iterate the routes config and make sure all controller/method & policies exist | ||
for (var path in routes) { | ||
if (!this.config.controllers[routes[path].controller]) { | ||
console.log(new Error(`Route ${path} controller "${routes[path].controller}" doesn\'t exist`)) | ||
process.exit() | ||
} | ||
else if (!this.config.controllers[routes[path].controller][routes[path].method]) { | ||
console.log(new Error(`Route ${path} controller method "${routes[path].controller}.${routes[path].method}" doesn\'t exist`)) | ||
process.exit() | ||
} | ||
const policies = (Array.isArray(routes[path].policies)) ? routes[path].policies : null | ||
const policies = (Array.isArray(routes[path].policies)) ? routes[path].policies : null; | ||
if (policies) { | ||
policies.forEach(p => { | ||
if (!this.config.policies[p]) { | ||
this.config.logger.warn(new Error(`Route ${path} policy "${p}" doesn't exist`)) | ||
process.exit() | ||
} | ||
}) | ||
} | ||
if (policies) { | ||
policies.forEach(p => { | ||
if (!this.config.policies[p]) { | ||
console.log(new Error(`Route ${path} policy "${p}" doesn\'t exist`)) | ||
process.exit() | ||
} | ||
}) | ||
} | ||
// if we've made it through all the checks, make the route | ||
const routeHandler = this.config.controllers[routes[path].controller][routes[path].method] | ||
this.makeRoute(path, routeHandler, policies) | ||
} // end for(..) | ||
} | ||
// if we've made it through all the checks, make the route | ||
const routeHandler = this.config.controllers[routes[path].controller][routes[path].method] | ||
this.makeRoute(path, routeHandler, policies) | ||
makeControllerRoutes () { | ||
// this will go through all of the controllers and assign a route/path and | ||
// handler for each controller method. ie: /{controllerFileName}/{methodName} | ||
// @NOTE it DOES NOT assign a route/path if the method has already been | ||
// declared in the routes config with a path THAT CONTAINS policies. | ||
} // end for(..) | ||
/** | ||
- if a controller method's name is `index` it is assigned to the filename | ||
endpoint without the methods name, ie: /{controllerFileName}/ will be the route | ||
- if a controller file export is a function, it is simply assign to the | ||
route /{controllerFileName} | ||
* | ||
*/ | ||
} | ||
const controllers = this.config.controllers | ||
makeControllerRoutes() { | ||
// this will go through all of the controllers and assign a route/path and | ||
// handler for each controller method. ie: /{controllerFileName}/{methodName} | ||
// @NOTE it DOES NOT assign a route/path if the method has already been | ||
// declared in the routes config with a path THAT CONTAINS policies. | ||
for (var controllerFileName in controllers) { | ||
const controller = controllers[controllerFileName] | ||
const path = '/' + controllerFileName | ||
/** | ||
- if a controller method's name is `index` it is assigned to the filename | ||
endpoint without the methods name, ie: /{controllerFileName}/ will be the route | ||
- if a controller file export is a function, it is simply assign to the | ||
route /{controllerFileName} | ||
* | ||
*/ | ||
// if the controller file export is a function, assign that route | ||
if (typeof controller !== 'object' && typeof controller === 'function') { | ||
this.makeRoute(path, controller) | ||
continue | ||
} | ||
const controllers = this.config.controllers | ||
// iterate controller file methods and assin routes | ||
for (var methodName in controller) { | ||
const method = controller[methodName] | ||
if (typeof controller[methodName] !== 'function') { | ||
this.config.logger.warn(new Error(`Controller method ${controllerFileName}.${methodName} is not a function`)) | ||
process.exit() | ||
} | ||
for ( var controllerFileName in controllers ) { | ||
const controller = controllers[controllerFileName] | ||
const path = "/" + controllerFileName | ||
// check controller.method is not specified in a route that contains a policy | ||
if (this.doesRouteWithPolicyExist(controllerFileName, methodName)) { | ||
continue | ||
} else if (methodName === 'index') { // check if methodName is `index` | ||
this.makeRoute(path + '/', method) | ||
continue | ||
} | ||
// if the controller file export is a function, assign that route | ||
if (typeof controller !== 'object' && typeof controller === 'function') { | ||
continue; this.makeRoute(path, controller) | ||
// assign route/handler | ||
this.makeRoute(path + '/' + methodName, method) | ||
} | ||
} | ||
} | ||
// iterate controller file methods and assin routes | ||
for ( var methodName in controller ) { | ||
const method = controller[methodName] | ||
if (typeof controller[methodName] !== 'function') { | ||
console.log(new Error(`Controller method ${controllerFileName}.${methodName} is not a function`)) | ||
process.exit() | ||
} | ||
makeRoute (path, handler, policies) { | ||
const route = this.config.router.route(path) | ||
// check controller.method is not specified in a route that contains a policy | ||
if (this.doesRouteWithPolicyExist(controllerFileName, methodName)) { | ||
continue; | ||
} | ||
// check if methodName is `index` | ||
else if (methodName === 'index') { | ||
this.makeRoute(path + "/", method) | ||
continue; | ||
} | ||
// assign route/handler | ||
this.makeRoute(path + "/" + methodName, method) | ||
// setup policies as middleware using `.all()` - they will get ran before | ||
// other http verbs. | ||
if (policies) { | ||
policies.forEach(p => { | ||
route.all(this.config.policies[p]) | ||
}) | ||
} | ||
} | ||
} | ||
// @TODO assign specific handlers per http verb | ||
// assign handler to route path for all http verbs | ||
route.get(handler).put(handler).post(handler).delete(handler) | ||
makeRoute(path, handler, policies) { | ||
const route = this.config.router.route(path) | ||
// setup policies as middleware using `.all()` - they will get ran before | ||
// other http verbs. | ||
if (policies) { | ||
policies.forEach(p => { | ||
route.all(this.config.policies[p]) | ||
}) | ||
// add route to our routeMap | ||
this.config.routeMap.push(path) | ||
} | ||
// @TODO assign specific handlers per http verb | ||
// assign handler to route path for all http verbs | ||
route.get(handler).put(handler).post(handler).delete(handler) | ||
// add route to our routeMap | ||
this.config.routeMap.push(path) | ||
} | ||
doesRouteWithPolicyExist (controller, method) { | ||
let exists = false | ||
doesRouteWithPolicyExist(controller, method) { | ||
let exists = false | ||
for (var path in this.config.routes) { | ||
if (exists) { return } | ||
for ( var path in this.config.routes ) { | ||
const route = this.config.routes[path] | ||
if (exists) { return } | ||
exists = route.controller === controller && | ||
route.method === method && | ||
(Array.isArray(route.policies) && route.policies.length) | ||
} | ||
const route = this.config.routes[path] | ||
exists = route.controller === controller && | ||
route.method === method && | ||
(Array.isArray(route.policies) && route.policies.length) | ||
return exists | ||
} | ||
return exists | ||
} | ||
} |
{ | ||
"name": "express-api-routes", | ||
"version": "1.1.2", | ||
"description": "", | ||
"description": "Node.js Express auto route & policy contructor for app servers", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1", | ||
"start": "node index.js" | ||
"test": "standard lib/** && mocha test/**", | ||
"start": "node index.js", | ||
"semantic-release": "semantic-release pre && npm publish && semantic-release post" | ||
}, | ||
@@ -14,7 +14,15 @@ "author": "Cory Robinson <coryrobinson42@gmail.com> (http://github.com/crobinson42)", | ||
"express": "^4.14.0", | ||
"node-watch": "^0.4.0" | ||
"winston": "^2.2.0" | ||
}, | ||
"devDependencies": { | ||
"express-list-endpoints": "2.0.x" | ||
} | ||
} | ||
"express-list-endpoints": "2.0.x", | ||
"mocha": "^3.0.2", | ||
"semantic-release": "^4.3.5", | ||
"standard": "^8.0.0" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/crobinson42/express-api-routes.git" | ||
}, | ||
"version": "1.1.3" | ||
} |
module.exports = { | ||
'/user/bam': { controller: 'user', method: 'doSomething', policies: ['authenticated','somepolicy'] } | ||
}; | ||
'/user/bam': { controller: 'user', method: 'doSomething', policies: ['authenticated', 'somepolicy'] } | ||
} |
module.exports = { | ||
index(req,res,next) { | ||
return res.send('Woohoo!'); | ||
index(req, res, next) { | ||
return res.send('Woohoo!') | ||
}, | ||
anotherOne(req,res,next) { | ||
return res.send('Did somethings!!'); | ||
anotherOne(req, res, next) { | ||
return res.send('Did somethings!!') | ||
} | ||
}; | ||
} |
module.exports = { | ||
index(req,res,next) { | ||
return res.ok('Woohoo!'); | ||
index(req, res, next) { | ||
return res.ok('Woohoo!') | ||
}, | ||
doSomething(req,res,next) { | ||
return res.send('Did somethings!!'); | ||
doSomething(req, res, next) { | ||
return res.send('Did somethings!!') | ||
} | ||
}; | ||
} |
@@ -1,4 +0,4 @@ | ||
module.exports = (req,res,next) => { | ||
console.log('some other policy...!!"'); | ||
next(); | ||
}; | ||
module.exports = (req, res, next) => { | ||
console.log('some other policy...!!"') | ||
next() | ||
} |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
17531
15
366
1
4
4
1
+ Addedwinston@^2.2.0
+ Addedasync@2.6.4(transitive)
+ Addedcolors@1.0.3(transitive)
+ Addedcycle@1.0.3(transitive)
+ Addedeyes@0.1.8(transitive)
+ Addedisstream@0.1.2(transitive)
+ Addedlodash@4.17.21(transitive)
+ Addedstack-trace@0.0.10(transitive)
+ Addedwinston@2.4.7(transitive)
- Removednode-watch@^0.4.0
- Removednode-watch@0.4.1(transitive)