Skip to content

Latest commit

 

History

History
116 lines (76 loc) · 4.92 KB

README.md

File metadata and controls

116 lines (76 loc) · 4.92 KB

bex

Express.js application bootstrapper. Simplicity, brevity, flexibility.

Build Status Coverage Status

NPM

Installation

npm i bex --save

Example

app.js

var config = require('./config').web;
var ong = require('ong').init();

require('bex').createApp({
	basedir: __dirname,
	bodyParser: { limit: '1mb' },
	viewEngine: require('express-dot').__express,
	hooks: { after: initialize }
}).listen(config.port);

function initialize (app) {
	ong.register('db', require('knex')(config.db));
	ong.register(this.requireAll(__dirname + '/modules'));
}

controllers/items.js

module.exports = {

	create: _.flow($.sanitize, $.validate, $.authorize, function (params) {
		return $.db('items').insert(params).then(this.json);
	}),

	'&/:id/render': function (params) {
		return Promise
			.props({ item: $.db('items').where('id', params.id).first() })
			.then(_.partial(this.view, 'items/index'));
	},

	'PUT items/:id/star': _.flow($.authorize, function (params) {
		return $.db('items').where('id', params.id).update('is_starred', 1).then(this.json);
	})

};

Quick notes (on example)

As you probably noted, there are 2 ways of specifying the route-handler pair:

  • implicit: via method names like list (GET resource), view (GET resource/:id), create (POST resource), update (PUT resource/:id) and remove (DELETE resource/:id)
  • explicit: by specifying exact route (GET resource/:from/:to) or exact route with resource name placeholder (GET &/:id) where kebab-cased controller's name will be substituted

In case of explicit route, you can omit GET verb, it is being used by default (&/:id is the same as GET &/:id or get &/:id).

What does it do?

  • creates express.js app
  • calls hook (before), if it is passed via hooks param
  • sets 'trust proxy' to true (very often node.js app is hosted behind nginx)
  • initializes view-related stuff, can be omitted by specifying views: false
  • initializes body-parser (almost every express.js-based project needs this)
  • creates router based on controllers modules (see example), can be omitted, if no controllers param is passed
  • calls hook (after), if it is passed via hooks param

Few words about route handling

  • it is expected, that route handler returns view result (or promise with view result): return this.json({ my: 'data' });
  • there are 3 built-it view results: view(name, data) (ends with rendering of name view with data), redirect(url) and json(data)
  • you can register your own result, which will be available via this inside route handler: bex.registerResult('myresult', function (anyarg) { return { type: 'myresult', arg: anyarg }; }); - minimal requirement for result constructor is to return result object with mandatory type property
  • you can register your own result handler, which will be called once result of given type is obtained from any of your route handlers: bex.registerHandler('myresult', function (req, res, result) { res.send(result.anyarg); });

There are 2 special results

  • exception - generated when exception occurs inside route handler (default handler will cause empty response with 500 code)
  • undefined - generated when no view result is returned from route handler (its default handler will cause empty response with 404 status)

You can override how bex reacts to these 2 special results (as well as other "ordinary" results) via overwriting their handlers: bex.registerHandler('exception', function (req, res, exception) { logstash.send(req.url, exception); }, true);.

Few words regarding hooks

  • there are 2 hooks: before (called just after express.js app is created, but nothing was performed with it) and after (called after everything is done and bex is ready to return bootstrapped app)
  • each hook will have this populated with utility methods: requireAll, registerResult, registerHandler, createRouter

Utility methods

requireAll(path)

Requires all modules which exist inside specified folder (see require-all docs for details).

regiserResult(name, value, [overwrite]) or registerResult(nameValueObject, [overwrite])

Registers view result(s).

regiserResult(name, value, [overwrite]) or registerResult(nameValueObject, [overwrite])

Registers view result handler(s).

createRouter(path)

Loads everything from specified path and maps converts to route-handler pairs, applying them to express.Router. Returns express.Router instance ready to be used by express.js app. Also accepts object as argument, each property-value of which will be treated as controllerName-controllerInstance pairs.

License

MIT