A module for grafting a function pipe (middleware) over other functions in nodejs.
A function pipe enables the management and execution of a series of operations between a source function and a target callback. Each operation in the series (often referred to as middleware) is executed in turn, potentially modifying the source's result, and ultimately, a caller provided target callback is invoked.
If you've used node for a while you are probably familiar with the function pipe pattern; it is used by connect, express, and flatiron to name a few. The goal of the fpipe module is to extract the function pipe behavior common to these great frameworks and encapsulate it for the community's use.
fpipe ensures executions of the pipeline are isolated from overlapping activity, including subsequent modifications to the pipe. It is useful for layering over asynchronous functions when numerous simultaneous executions are anticipated.
npm install fpipe
npm test fpipe
var util = require'util'fpipe = require'fpipe';// Gets a random integer between 0 (zero) and maxreturn MathfloorMathrandom * max+1;// Waits a random period of time before returning a dumb message to the// callback given.// simulate latencyvar wait = randomWait1000;setTimeoutcallbacknull "It took me "concatwait " milliseconds to notice you.";wait;// Logs it then calls next.util.logutilinspectit;nextnull it;// Observes it (by writing it to the console), then calls next.console.log"observed: "concatit;nextnull it;// Create an fpipe over our uninteresting function...var pipe = fpipecreatedo_something_uninteresting;// Add some middleware...pipeuselogIt;pipeuseobserveIt;// Execute the pipe...pipeexecuteif errconsole.log"Got an error: "concatutilinspecterr false 99;elseconsole.log"Got a message: "concatres;;
An standard import of fpipe
var fpipe = require('fpipe') is assumed in all of the code examples. The import results in an object having the following public properties:
create- a factory for creating fpipes.
log_sink- a shared event emitter where any uncaught exception are exposed.
Pipe- the fpipe implementation class.
version- exposes the module's version.
Constructs a new function pipe.
// Create a pipe without a source function...var my = fpipecreate;
// Create a pipe over a source function...var my = fpipecreatecallbacknull here_is: "a result" ;;
A function pipe derives from Node.js' EventEmitter and exposes the following interface:
_source- the source function over which the pipe will execute.
_middleware- an array containing the currently configured middleware on the pipe; this is the series of functions that will execute between the source function and the target callback.
use- adds a middleware function to the series of functions that the pipe will execute.
execute- invokes the source function, the middleware series, and ultimately the target callback.
source- sets the pipe's source function.
clone- clones the pipe, optionally changing it's source function.
- "uncaughtException" - occurs when the pipe encounters an uncaught exception. Generally speaking, this only occurs when your callback throws. Exceptions occurring during the series are given to your callback directly (as per the Node.js callback style).
Adds a middleware function to the series of functions that the pipe will execute.
middleware- a middleware function (described below).
To be useful, any
middleware function should take the following 2 arguments.
res- the result of the predicessor step in the middleware pipeline.
next- the next middleware step in the pipeline.
Well behaved middleware will always call
next function is a callback in the Node.js style:
next function behaves like this:
if err// a prior function in the series resulted in error,// stop the pipe and notify the target callback...thisnotifyTargetOfErrorerr;else// no error yet, continue processing...thisperformNextMiddlewareres;
Example of well-behaved (albeit trivial), middleware function:
var my = fpipecreatecallbacknull here_is: "a result" ;;myuseconsole.logutilinspectres;nextnull res;;
If a middleware function throws an error it will be caught by the Pipe. The pipe will behave as if the middleware returned the error to
Executes the function pipe, starting with the
source function that you provided, then continuing with each
middleware in turn, and finally ending by invoking the
callback- a nodejs style callback taking an error and a result.
any..any-n- any value(s) that must be curried to the source function
var util = require'util'fpipe = require'fpipe';var pipe = fpipecreate;pipeusevar modified = res? 'Observed: 'concatres: 'Observed nothing.';nextnull modified;;// Create a pipe over a function that does not take any arguments// other than the callback...pipesourcecallbacknull "Somebody poked me!";;// Execute the pipe, providing a callback.pipeexecuteif errconsole.log'Got an error: ' + err;elseconsole.log'Got a result: ' + res;;// Create a clone, replacing the source with// a function that expects an argument...var pipe2 = pipeclone// simulate some latency, then say hi...setTimeoutcallbacknull 'Hi ' + you;1000;;// Since the source of second pipe takes an argument,// we pass it after our callback. Any arguments following// the callback are curried to the source in front of// the callback so you'll want to ensure that enough// arguments are passed (even if some are null) so that// the callback is positioned correctly.pipe2executeif errconsole.log'Got an error: ' + err;elseconsole.log'Got a result: ' + res;'tester';