Skip to content

Commit

Permalink
improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
muhammaddadu committed Jan 12, 2017
1 parent 1733b78 commit 15199e7
Show file tree
Hide file tree
Showing 9 changed files with 272 additions and 159 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,12 @@ module.exports = {
}
}
```

### Enviromental Config
- development (DEFAULT)
- <enviroment>

These enviromental variable can be set using NODE_ENV=<enviroment>.

These configuration files can be stored in ```/conf``` with <name>.<env>.js with default.<env>.js always

58 changes: 29 additions & 29 deletions hooks/apis.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@
*/
const
debug = require('debug')('clout:hook/apis'),
Q = require('q'),
path = require('path');
utils = require('../lib/utils')
path = require('path'),
utils = require('../lib/utils'),
express = require('express'),
router = express.Router();

Expand All @@ -25,42 +24,50 @@ module.exports = {
function loadAPI(dir) {
var group = dir.split('apis/')[1].replace('.js', '');
debug('loading apis from %s', group);
var apis = require(dir);
try {
var apis = require(dir);
} catch (e) {
throw new Error('Error loading api group `' + group + '`: ' + e);
}
Object.keys(apis).forEach(function loadApi(apiName) {
debug('loading api %s:%s', group, apiName);
var api = apis[apiName];
if (!api.path) {
return;
}
// allow .ext
api.path += '(.:acceptType)?';
api.path += '\.:acceptType?';

var hooks = api.hooks || [],
method = api.method ? api.method.toLowerCase() : 'all';
methods = api.methods
? api.methods
: [api.method || 'all'];

methods = methods.map((method) => method.toLowerCase());

// log endpoint request
router[method](api.path, function (req, res, next) {
methods.forEach((method) => router[method](api.path, function (req, res, next) {
req.logger.info('Endpoint [%s] /api%s', req.method, req.path);
debug('Endpoint [%s] /api%s', req.method, req.path);
next();
});
}));

// load hook first
hooks.forEach(function (hook) {
if (typeof hook === 'string') {
// implement smart hooks
return;
}
router[method](api.path, function (req) {
methods.forEach((method) => router[method](api.path, function (req) {
hook.name && debug('hook:', hook.name);
hook.apply(this, arguments);
});
}));
});

// load api
if (api.fn) {
debug('loaded endpoint [%s] /api%s', method, api.path);
router[method](api.path, function (req) {
methods.forEach((method) => router[method](api.path, function (req) {
debug('loaded endpoint [%s] /api%s', method, api.path);
// allow .ext
if (req.params.acceptType && ACCEPT_TYPES[req.params.acceptType]) {
var acceptType = ACCEPT_TYPES[req.params.acceptType];
Expand All @@ -69,34 +76,27 @@ module.exports = {
};
debug('loading api %s:%s', group, apiName);
api.fn.apply(this, arguments);
});
}));
}
});
}

function loadAPIsFromDirectory(dir) {
var deferred = Q.defer(),
dirs = utils.getGlobbedFiles(path.join(dir, '**/**.js'));
var dirs = utils.getGlobbedFiles(path.join(dir, '**/**.js'));
dirs.forEach(loadAPI);
deferred.resolve();
return deferred.promise;
}

debug('loading apis');
// 1) load module hooks
async.each(this.modules, function (module, next) {
loadAPIsFromDirectory(path.join(module.path, 'apis')).then(function () {
next(null);
}, next);
}, function done(err) {
if (err) { throw new Error(err); }
// 2) load application hooks
loadAPIsFromDirectory(path.join(self.rootDirectory, 'apis')).then(function () {
debug('attached router');
self.app.use('/api', router);
next();
}, next);
this.modules.forEach(function (module) {
loadAPIsFromDirectory(path.join(module.path, 'apis'));
});
// 2) load application hooks
loadAPIsFromDirectory(path.join(self.rootDirectory, 'apis'));
// 3) attach router
debug('attached router');
self.app.use('/api', router);
next();
}
}
};
160 changes: 92 additions & 68 deletions hooks/middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,25 @@
* Copyright(c) 2015 - 2016 Muhammad Dadu
* MIT Licensed
*/
const
fs = require('fs-extra'),
path = require('path'),
express = require('express'),
debug = require('debug')('clout:hook/middleware'),
compress = require('compression')
bodyParser = require('body-parser'),
cookieParser = require('cookie-parser'),
session = require('express-session');
const fs = require('fs-extra');
const path = require('path');
const express = require('express');
const debug = require('debug')('clout:hook/middleware');
const compress = require('compression');
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const session = require('express-session');
const Q = require('q');

const DEFAULT_HTML_RENDER = 'htmljson';

module.exports = {
initialize: {
event: 'start',
priority: 1,
fn: function (next) {
// TODO:-
// - move to Clout.js for initialization
this.app = express();
this.app.set('x-powered-by', 'Clout-JS');
this.app.set('env', this.config.env);
Expand All @@ -27,7 +31,7 @@ module.exports = {
this.app.use(bodyParser.json());
debug('loaded bodyParser.json()');
this.app.use(bodyParser.urlencoded({
extended: false
extended: true
}));
debug('loaded bodyParser.urlencoded()');
this.app.use(bodyParser.text({}));
Expand All @@ -51,17 +55,18 @@ module.exports = {
event: 'start',
priority: 'MIDDLEWARE',
fn: function (next) {
var sessionConf = this.config.session || {};
if (!sessionConf.secret) {
this.logger.warn('session.secret is undefined');
sessionConf.secret = '1c6bf8c5cef18097a5389c3ca6d73328';
}
if (!sessionConf.hasOwnProperty('resave')) {
sessionConf.resave = true;
}
if (!sessionConf.hasOwnProperty('saveUninitialized')) {
sessionConf.saveUninitialized = false;
}
let sessionConf = this.config.session || {};

!sessionConf.secret
&& this.logger.warn('session.secret is undefined')
&& (sessionConf.secret = '1c6bf8c5cef18097a5389c3ca6d73328');

!sessionConf.resave
&& (sessionConf.resave = true);

!sessionConf.saveUninitialized
&& (sessionConf.saveUninitialized = false);

this.config.session = sessionConf;
this.app.session = session(sessionConf);
this.app.use(this.app.session);
Expand All @@ -72,41 +77,45 @@ module.exports = {
event: 'start',
priority: 'MIDDLEWARE',
fn: function (next) {
var self = this;
function useDir(dir) {
let useDir = (dir) => {
if (!fs.existsSync(dir)) { return; }
debug('appending public dir %s', dir);
self.app.use(express.static(dir));
this.app.use(express.static(dir));
}

// application public folder
useDir(path.join(this.rootDirectory, 'public'));

// modules
this.modules.forEach(function (module) {
useDir(path.join(module.path, 'public'));
});
this.modules.forEach(module => useDir(path.join(module.path, 'public')));

// clout public folder
useDir(path.join(__dirname, '../resources/public'));

next();
}
},
views: {
event: 'start',
priority: 'MIDDLEWARE',
fn: function (next) {
var views = [];
let views = [];

function useDir(dir) {
if (!fs.existsSync(dir)) { return; }
debug('appending views dir %s', dir);
views.push(dir);
}

// application public folder
useDir(path.join(this.rootDirectory, 'views'));

// modules
this.modules.forEach(function (module) {
useDir(path.join(module.path, 'views'));
});
this.modules.forEach(module => useDir(path.join(module.path, 'views')));

// clout public folder
useDir(path.join(__dirname, '../resources/views'));

// set views
this.app.set('views', views);
next();
Expand All @@ -126,59 +135,74 @@ module.exports = {
event: 'start',
priority: 'MIDDLEWARE',
fn: function (next) {
var httpResponseMap = this.config.httpResponseMap,
methods = Object.keys(httpResponseMap);
var httpResponseMap = this.config.httpResponseMap;

function jsonFormat(method, context, payload) {
return () => {
context
.type('json')
.status(method.code)
.send(JSON.stringify(payload));
}
}

function htmlFormat(method, context, payload) {
return () => {
!method.render && (method.render = DEFAULT_HTML_RENDER);
context
.status(method.code)
.render(method.render, {
data: payload
});
}
}

// TODO:-
// - refactor to add support for more file types (CSV, XML)
// - success: false should point to an error html response
methods.forEach(function (methodName) {
var method = httpResponseMap[methodName];
for (let methodName in httpResponseMap) {
let method = httpResponseMap[methodName];

if (typeof express.response[methodName] !== 'undefined') {
clout.logger.warn('overiding express response method `%s`', methodName);
}

express.response[methodName] = function (data) {
var self = this,
format = {},
payload = _.merge({
data: data
}, {
code: method.code,
success: method.method
});
format.text =
format.json = function () {
self
.type('json')
.status(method.code)
.send(JSON.stringify(payload));
}
format.html = function () {
!method.render && (method.render = 'htmljson');
self
.status(method.code)
.render(method.render, {
data: payload
});
}
this.format(format);
let deffered = Q.defer();
let payload = {
data: data,
code: method.code,
success: method.method
};

// bind our formaters
let jsonFormatFn = jsonFormat(method, this, payload);
let htmlFormatFn = htmlFormat(method, this, payload);

// let express choose the format
this.format({
text: jsonFormatFn,
json: jsonFormatFn,
html: htmlFormatFn,
default: htmlFormatFn
});

deffered.resolve();
return deffered.promise;
};
});
}
next();
}
},
leastButNotLast: {
errorHandler: {
event: 'start',
fn: function (next) {
next();
this.app.use(function (err, req, resp, next) {
if (!err) { return next(); }

req.logger.error(err.stack);
resp.error(err);
});

// Assume 404 since no middleware responded
this.app.use(function (req, resp) {
resp.notFound();
});
next();
}
}
};
2 changes: 1 addition & 1 deletion hooks/models.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ module.exports = {
try {
self.models[modelName] = require(dir);
} catch (e) {
throw new Error('Error loading model `' + modelName + '`: ' + e)
throw new Error('Error loading model `' + modelName + '`: ' + e);
}
});
}
Expand Down
Loading

0 comments on commit 15199e7

Please sign in to comment.