The thorin middleware

You can define middleware functions by registering them in the dispatcher (using a name) and use them in your application's action definition. Your middleware functions should contain simple functionality and alter the incoming intentObj by overriding input data, or pass data from one middleware to the next, by using the data() function of an intent.

The core middleware class is under thorin.Middleware and can be extended by other thorin components, using the pattern below:

'use strict';
const CoreMiddleware = thorin.Middleware;
thorin.Middleware = class ThorinMiddleware extends CoreMiddleware {
   constructor(name) {
      super(name);
      // your custom functionality
   }
}
Functionality
Properties
  • namestring the middleware name
middlewareObj.input(obj)
Adds an input validator to the middleware before calling any use() functions from the call stack.
  • objobject An object containing validation rules for the incoming input.
middlewareObj.use(name, opt)
A middleware can make use of other middlewares by registering them as a named middleware requirement with use("middlewareName"). A middleware can also register an anonymous handler using use((intentObj, next, opt) => {}), that will receive the incoming intent object as well as any options that were passed by higher dependencies. (see below)
  • namestring | function the name of the middleware to use as a dependency or the function of the inline handler
  • optobject when using another middleware as a dependency, you can pass options to it.
middlewareObj.end(fn)
Registers a function that will be called once the middleware has completed its call stack. This is useful for logging and other post-middleware actions
  • fnfunction the function to call when the middleware has ended
middlewareObj._runStack(intentObj, opt, done)
Similar to the action's _runStack function, it will execute the internal middleware call stack in the chronological order they were defined. This is usually called by the dispatcher.
  • intentObjinstance of thorin.Intent the current intent object
  • optobject additional options passed by the higher dependents
  • donefunction the function to call once the run stack has been called.
Example
'use strict';
const dispatcher = thorin.dispatcher;
// Register our middleware.
dispatcher
   .addMiddleware('mid.one')
   .input({
      name: dispatcher.validate('STRING') // it will fail with a generic error if no name is provided
   })
   .use((intentObj, next, opt) => {
      log.info(`Should process action ${intentObj.action} using middleware options `, opt);
      if(opt.nickname) {
         intentObj.data('nick', 'A silly object name');
      }
      next();
   });

// Add a separate middleware
dispatcher
   .addMiddleware('mid.two')
   .use('mid.one', {
      nickname: true
   })
   .use((intentObj, next) => {
      log.info(`Got nickname: ${intentObj.data('nick')}`);
      next();
   });

// Add an action that will use the second middleware.
dispatcher
   .addAction('home.example')
   .use('mid.two')
   .use((intentObj, next) => {
      log.info(`Done`);
      intentObj.result({
         nick: intentObj.data('nick')
      }).send();
   });
Do you have a question or is something missing?

You can always create a new issue on GitHub or contact one of the core founders by chat.