Ginga.js
Ginga is a utility module that enables a middleware based (express inspired), modular architecture for creating asynchronous JavaScript function. Supports both callback and promise.
npm install ginga
ginga([object])
Initialise ginga
var ginga = require('ginga')
var obj = ginga()
var app = {}
ginga(app)
function App () { }
ginga(App.prototype)
Method and Hook
app.define(name, [pre...], invoke)
app.use(name, [hook...])
define()
and use()
a method with pre
, hook
, invoke
middleware functions.
pre
middlewares initiate and batch operations where invoke
commits result.
hook
can be mounted for additional validations or amendments.
Ginga method supports both callback and promise.
Middleware
Middleware turns asynchronous functions into encapsulated, reusable set of building blocks.
Upon calling a method, Ginga method goes through a sequence of middleware functions, with following arguments:
ctx
- context event emitter object:
- Maintains state throughout the method call, while encapsulated from
this
object. - A middleware can make changes to context object, or access changes made by previous middleware.
- Emits end event
ctx.on('end', fn)
on callback with error and result arguments.
next
- callback function:
next()
to pass control to the next middleware.next(err, result)
to end the sequence and callback with error or result.
var ginga = require('ginga')
var app = ginga()
app.define('test', function (ctx, next) {
ctx.logs = ['pre']
next()
}, function (ctx, done) {
ctx.logs.push('invoke')
done(null, ctx.logs)
})
app.use('test', function (ctx, next) {
ctx.logs.push('hook')
setTimeout(next, 10)
})
app.test(function (err, res) {
console.log(res)
})
app.test().then(function (res) {
console.log(res)
})
shortcuts for callback functions:
function (ctx, next) {
task(function (err, res) {
if (err) return next(err)
next()
})
}
function (ctx, next) {
task(next(function (res) {
}))
}
ginga.params([param...])
Ginga built in ginga.params
middleware for parsing method arguments. Supports optional parameters and type-checking.
param
is string in form of
name[:type][?]
name
- name of parameter mapped from argumenttype
type checking (optional): string
, boolean
, function
, number
, date
, regexp
, object
, array
, case insensitive.?
- optional parameter.
var ginga = require('ginga')
var params = ginga.params
var app = ginga()
app.define('test', params('a', 'b:number?', 'c:string?'), function (ctx, done) {
done(null, ctx.params)
})
app.test('s', 1, function (err, res) {
console.log(res)
})
app.test('s', 't', function (err, res) {
console.log(res)
})
app.test(function (err, res) {
console.log(err)
})
Plugin
app.use(plugin)
app.use
also accepts Ginga object as plugin. This will mount hooks into the main app.
var ginga = require('ginga')
var app = ginga()
app.define('test', function (ctx, next) {
ctx.logs = ['pre']
next()
}, function (ctx, done) {
ctx.logs.push('invoke')
done(null, ctx.logs)
})
var plugin = ginga()
plugin.use('test', function (ctx, next) {
ctx.logs.push('plugin')
next()
})
app.use(plugin)
app.test(function (err, res) {
console.log(res)
})
Inheritance
By initialising Ginga with prototype mixin, hooks are also inherited in prototype chain:
var ginga = require('ginga')
function App () { }
var A = ginga(App.prototype)
A.define('test', function (ctx, next) {
ctx.logs = ['pre']
next()
}, function (ctx, done) {
ctx.logs.push('invoke')
done(null, ctx.logs)
})
var a1 = new App()
var a2 = new App()
A.use('test', function (ctx, next) {
ctx.logs.push('A hook')
next()
})
a1.use('test', function (ctx, next) {
ctx.logs.push('a1 hook')
next()
})
a2.use('test', function (ctx, next) {
ctx.logs.push('a2 hook')
next()
})
a1.test(function (err, res) {
console.log(res)
})
a2.test(function (err, res) {
console.log(res)
})
License
MIT