usey

1.9.5 • Public • Published

usey

Generic middleware/plugin framework inspired by express.js's .use()

about

build status

This module generates a single function which when called will pass the values passed to it to each of the functions specified with the .use() method. If one of the functions passes an error to the next() function the main callback will be immediately called (if specified) and no functions further in the chain will be processed.

This is inspired by the express.js .use() method and is a generic implementation of it.

install

npm install usey

basic example

var Usey = require('usey');

var app = Usey();

app.use(function (obj1, obj2, next) {
   obj1.x += 1;
   obj2.y += 1;

   return next();
});

app.use(function (obj1, obj2, next) {
   obj1.x += 2;
   obj2.y += 2;

   return next();
});

app({ x : 0 }, { y : 0 }, function (err, obj1, obj2) {
   console.log(arguments);
});

named chains example

var Usey = require('usey');

var app = Usey();

//do a thing, and then goto cleanup
//going to cleanup because of this is not going to happen
//because doThing is going to throw an error
app.use(doThing, Usey.goto('cleanup'));

//use the goto helper to jump to the cleanup chain when
//and if the error chain gets hit
app.use('error', Usey.goto('cleanup'))
app.use('cleanup', doCleanup)

app({ x : 0 }, function (err, obj) {

});

function doThing (obj, next) {
	//throwing an error will cause the 'error' chain
	//to be called
	return next(new Error("this thing failed"));
}

function doCleanup (obj, next) {
	return next();
}

usage

Create an instance

When you create an instance by calling Usey(), it returns a function. That function has one method: .use().

var Usey = require('usey');
var u = Usey(); //this creates the instance function

The Usey constructor takes an options object with the following options:

  • context : [object] this is the context (the this value) for each of the functions passed to the use() function and for the main callback.
    • By default a new empty object created when calling the usey instance function and that is used as the context for each function passed to use()
  • timeout : [number] a numeric value that specifies the maximum number of milliseconds to wait for any of the .use() specified functions to callback
  • stackNames : [boolean] if true, when .use() is called, we will use stack traces to determine where the function was defined. This information is used when debugging
  • debug : [function] an optional function that will be called with debug information. If not defined, it defaults to using the debug module.

Add middleware/plugins/functions

When you call the .use() method, you may pass it a single function, an array of functions or many functions as arguments.

u.use(fn1);
u.use([fn2, fn3, fn4]);
u.use(fn5, fn6, fn7, fn8);
u.use(fn9);

Remove middleware/plugins/functions

When you call the .unuse() method passing it a function reference, you can remove that function from the processing chain.

u.unuse(fn9);

Inserting / unshifting middleware/plugins/functions

You can insert a function to specific position using .insert() or .unshift()

//put the function f10 at the beginning of a chain
u.unshift(f10);

//put the function f11 at some specific position
u.insert(5, f11);

//you can also to it to named chains
u.unshift('error', logErrorMessage);

u.insert('cleanup', 4, closeDatabase);

Call the main function

Now when you call u(arg1, arg2, arg3, ..., function (err, arg1, arg2, arg3, ...){}), it will in turn call, in order:

fn1(arg1, arg2, arg3, ..., next);
fn2(arg1, arg2, arg3, ..., next);
fn3(arg1, arg2, arg3, ..., next);
fn4(arg1, arg2, arg3, ..., next);
fn5(arg1, arg2, arg3, ..., next);
fn6(arg1, arg2, arg3, ..., next);
fn7(arg1, arg2, arg3, ..., next);
fn8(arg1, arg2, arg3, ..., next);
fn9(arg1, arg2, arg3, ..., next);

However, it will only call each function after the currently executing function calls the next() method.

var obj = {};
u(obj, function (err, obj) {
	console.log(obj);
});

Named Function Chains

You may call the .use() method passing it a string as the first argument. That string should be the name of a chain. You can then call that chain from another.

The named chain error is a special named chain that will be called if an error is passed to the next() callback at any time. The error named chain will be processed before the main callback will be called. This is helpful for cleaning up after errors have occurred.

var u = Usey();

u.use(openDatabase('mydatabase'));
u.use(beginTransaction);
u.use(insertOrderHeader);
u.use(insertOrderItems);
u.use(commitTransaction);
u.use(goto('finally'));
u.use('finally', closeDatabase);
u.use('finally', closeRedis);
u.use('error', rollbackTransaction);
u.use('error', goto('finally'));

u(order, function (err) {
	//done
});

function openDatabase(db) {
	return function () {
		var self = this
			, next = getNext(arguments);

		//this is hypothetical
		mysql.open(db, function (err, client) {
			if (err) {
				return next(err);
			}

			self.db = client;

			return next();
		});
	}
}

function beginTransaction() {
	var next = getNext(arguments);

	this.db.beginTransaction(next);
}

function goto(name) {
	return function () {
		var next = getNext(arguments);

		next(name);
	}
};

function getNext(a) {
	return a[a.length -1];
}

http server example

var Usey = require('usey')
   , responseTime = require('response-time')
   ;

var app = Usey();

app.use(responseTime()) //this middleware adds a X-Response-Time http header
   .use(Redirect) //this middleware attaches .redirect() to the response object
   .use(Router(app)) //this middleware attaches .get() and .post() methods to app
   .use(_404) //this middleware is called last

app.get('/test', function (req, res, next) {
   return res.end('hello');
});

app.get('/redirect-me', function (req, res, next) {
   return res.redirect('https://www.npmjs.org');
});

var server = http.createServer(app)

server.listen(1337);

function Redirect(req, res, next) {
   //append redirect method to response object
   res.redirect = function (url) {
      res.writeHead(302, {
         Location : url
      });
   };

   return next();
}

function Router(app) {
   var routes = [];

   ['get', 'post'].forEach(function (method) {
      app[method] = addRoute.bind(app, method)
   });

   app.add = addRoute;

   function addRoute (method, path, handler) {
      routes.push({
         method : method.toUpperCase()
         , path : path
         , handler : handler
      });

      return app;
   }

   return function (req, res, next) {
      var route;
      for (var x = 0; x < routes.length; x ++ ){
         route = routes[x];

         if (route.method == req.method && route.path == req.url) {
            return route.handler(req, res, next);
         }
      };

      return next();
   }
}

function _404 (req, res, next) {
   res.writeHead(404);
   res.end('File not found');
}

license

MIT

Package Sidebar

Install

npm i usey

Weekly Downloads

7

Version

1.9.5

License

MIT

Unpacked Size

31 kB

Total Files

7

Last publish

Collaborators

  • wankdanker