Plugin architecture in HapiJS

Plugin architecture in HapiJS
As we had talked about creating REST APIs with HapiJS framework, let talk about ease of creating apps in HapiJS; for that we have plugin architecture in HapiJS. Plugin Architecture will help you in creating your apps as a dependency and keeps the things separated.With plugins, you can share the objects between different parts of application via server parameter rather than the awkward require with multiple ../.

Basic

The plugin architecture goes as follows:

let Plugin = {};

Plugin.register = (server, options, next) => {
  // Do some stuff with server

  // Let hapijs know that you are done and move to next plugin
  next();
};

Plugin.register.attributes = {
  name: 'MyAwesomePlugin',
  version: '0.1.0'
};

module.exports = Plugin;

In above code, before next();, you can do anything which you might do while creating a regular server file; other than starting the server.

Creation

Let’s take a look at following example. In this example we will register the plugin hapi-response-time and add a route named ping for health-check purpose:

// file: plugins/ping.js
const Plugin = {};

Plugin.register = (server, options, next) => {
  // Do some stuff with server
  server.register(require('hapi-response-time'), (err) => {
    if (err) throw err;
  });

  server.route([{
    method: ['GET', 'POST'],
    path: '/ping',
    handler: (req, reply) => {
      reply('Hello world!');
    }
  }]);

  // Let hapijs know that you are done and move to next plugin
  next();
};

Plugin.register.attributes = {
  name: 'MyAwesomePlugin',
  version: '0.1.0'
};

module.exports = Plugin;

Usage

In the main server file, where you will create and start the server, the above plugin can be registered as follows:

'use strict';

const Hapi = require('hapi');
const server = new Hapi.Server();

server.connection({
  host: 'localhost',
  port: Number(process.argv[2]) || 8080
});

// Add the route
server.route({
  method: 'GET',
  path: '/',
  handler: function (request, reply) {
    return reply('HapiJS Server running!');
  }
});

server.register(require('hapi-response-time'), err => {
  if (err) throw err;
});

// Start the server
server.start((err) => {
  if (err) {
    throw err;
  }
  console.log('Server running at:', server.info.uri);
});

Advanced

As you have noticed, the register method of the plugin has three parameters: server, options and next. The options was not used. The options parameter is for providing configuration values to the plugin. Consider a scenario in above example where you want to name the ping route as per your choice and enable it for only specified HTTP methods or not wanting the route at all. The plugin’s register method will look like follows:

Creation

Plugin.register = (server, options, next) => {
  server.register(require('hapi-response-time'), (err) => {
    if (err) throw err;
  });
  if (options.route) {
    server.route([{
      method: options.route.methods || ['GET', 'POST'],
      path: `/${options.route.name || 'ping'}`,
      handler: (req, reply) => {
        reply(options.route.message || 'Hello world!');
      }
    }]);
  }
  next();
};

The options for new plugins are:
route which is either false or Object === {name: ”, methods: [], message: ”}

Usage

Then this plugin can be used in following ways:

No route is needed

server.register({
    register: require('hapi-response-time'),
    options: {
        route: false
    }
}, err => { if (err) throw err; });

Route is named as health

server.register({
    register: require('hapi-response-time'),
    options: {
        route: {
            name: 'health'
        }
    }
}, err => { if (err) throw err; });

Route is only for POST method

server.register({
    register: require('hapi-response-time'),
    options: {
        route: {
            name: 'health',
            methods: ['POST']
        }
    }
}, err => { if (err) throw err; });

Route has custom message

server.register({
    register: require('hapi-response-time'),
    options: {
        route: {
            message: 'Hello from MyAwesomePlugin'
        }
    }
}, err => { if (err) throw err; });

Conclusion

The possibility are endless when you let your imagination fly. Please let us know your feedback about this post in the comments section. If you face any problem, you can ask and discuss with us in comments section as well.

Happy Coding!