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
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.
app.define(name, [pre...], invoke)
app.use(name, [hook...])
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')
next()
})
app.test(function (err, res) {
console.log(res)
})
app.test().then(function (res) {
console.log(res)
})
Middleware
Middleware turns asynchronous function into encapsulated, reusable set of building blocks.
Upon calling a method, Ginga goes through a sequence of functions middleware
. A middleware consists of arguments:
ctx
- context event emitter object. Emits .on('end', fn)
event on callback with error and result arguments.next
- callback function, invoke with next()
or next(err, result)
or asyncFn(next(resolveFn))
The context object ctx
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 functions.
Given next argument, current middleware must call next()
to pass control to the next middleware, or next(err, result)
to end the sequence and callback with error or result.
Otherwise the method will be left hanging.
ginga.params([param...])
Ginga built in ginga.params
middleware for parsing method arguments. Supports optional parameters and type-checking.
param
is a string in form
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