hapi plugins

We've seen briefly in the previous chapters how to register third-party plugins to a hapi server, and the power that they have in being able to add custom handlers, routes, or print our routing table on startup. hapi's plugin system is powerful, extensive, and at the level where not only is the plugin system useful for integrating third-party modules, but also a great abstraction for breaking up your application into smaller, reusable chunks of code. Let's take one of our examples from the previous chapters, and show how we can break up our business logic into more manageable chunks using plugins.

Encapsulating functionality within plugins

If you remember, in the first chapter, we looked at what a full server with a single route added to it looks like, and used the blipp module to print the routing table on server start. In the example, all the code is contained in one entry file. As long as you have one route, this is fine; however, as an application grows, this practice leads to code with a structure that is harder to understand and follow.

In fact, as a rule when developing with hapi, I never put any business logic in my entry server file; all logic must be pushed into a plugin. This makes the code base much more readable, as all the code within the plugin now has context. Let's attempt this with an example, and create our first plugin. Let's start with a server very similar to the one we created in Chapter 1, Introducing hapi.js:

'use strict';
const Hapi = require('hapi');
const Blipp = require('blipp');
const server = new Hapi.Server();
server.connection({ port: 1337, host: '127.0.0.1' });
server.route({
  method: 'GET',
  path: '/hello',
  handler: function (request, reply) {
    return reply('Hello World
');
  }
});
server.register(Blipp, (err) => {
  server.start((err) => {
    console.log(`Server running at ${server.info.uri}`);
  });
});

Here, the business logic that should be removed is that of adding a route to the server. This can be abstracted away to a plugin. Let's look at what is involved in creating our first plugin. First we will create a file that we will call hello.js, and in this, we'll add the code for our first plugin and our /hello route:

exports.register = function (server, options, next) {
  server.route({
    method: 'GET',
    path: '/hello',
    handler: function (request, reply) {
      return reply('Hello World
');
    }
  });
  next();
};
exports.register.attributes = {
  name: 'hello'
};

Not too complicated, right? A hapi plugin is an object with a register function that accepts three parameters:

  • server: It is a reference to the parent server object.
  • options: It is an object of options that can be passed when registering the plugin (we'll look at this when registering our new plugin).
  • next: It is a method to be called when you finish registering your plugin, and return the control back to the framework. While not used here, it's worth noting that it accepts one parameter, err, that should only be defined if there was an error registering the plugin. In practice, this is usually left undefined. This allows for plugins to do asynchronous operations when registering, which is hugely advantageous; we will explore this later.

The register function then has an attributes object attached to it for providing hapi with further information about the plugin.

Now that we have our own plugin, let's modify the original server example so that it now registers this new plugin instead of adding the /hello route. We'll also look in more detail at what happens when we call server.register():

'use strict';
const Hapi = require('hapi');
const Blipp = require('blipp');
const Hello = require('./hello');
const server = new Hapi.Server();
server.connection({ port: 1337, host: '127.0.0.1' });
server.register([
  { register: Hello, options: {} },
  Blipp
], (err) => {
  server.start((err) => {
    console.log(`Server running at ${server.info.uri}`);
  });
});

Now we have successfully moved all our business logic to our plugin, and simplified our entry file. Hopefully, this makes for very readable code, and you're beginning to see how this could scale quite nicely as the codebase expands.

You might have noticed that we are passing an array to the register function now; this is because the register function can accept a single plugin object, or an array of plugin objects. The first plugin that we pass is our newly created plugin, Hello. The options object passed here maps to the second parameter in the plugin's register function. As we have no options that we need to pass in here, this has been left empty. When passed an array of plugins, the register function will iterate through each plugin, perform all actions in the register function until it reaches the next() call, and then move on to the next plugin. When all plugins are registered, it will finally call the callback passed to the register function, which, in this case, just starts our server.

Plugin options

There is a second optional object that you can pass to server.register() before the callback. These options are used by hapi, and are not to be confused with the options object we pass to a plugin.

The second options parameter allows you to configure some special options when registering a plugin, such as a route prefix, where the string provided will be prefixed to all the route paths registered within the plugin.

Another option that can be used is vhost, where the routes registered within the plugin will only be available to clients with a matching vhost in the request header.

Let's look at an example of plugin options in action. Let's add a prefix of /v1 to the routes registered within our Hello plugin:

…
server.register(
  { register: Hello, options: {} },
  {
    routes: {
      prefix: '/v1'
    }
  }, (err) => {
  // start server
});
…

If we registered our plugins like this, our new Hello plugin would now register a route with the path /v1/hello instead of /hello. This can be very useful for versioning APIs.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.7.131