Christian Giacomi

Custom events in Hapi

Posted — Apr 7, 2019

For those of you that are not familiar with Hapi, let me just say that it’s a wonderful nodejs framework. There are no other words that I can use to describe it. It’s not only a high performance framework but it is also a framework that makes it fun to work with.

Personally I love that the framework has built in support for plugins, as they allow the code to be completely modular without the middleware nightmare that other frameworks suffer from.

Most importantly the framework is very well maintained and groomed. It is an opinionated framework and one that offers a lot of features.

I have personally used Hapi for REST API’s and when working with nodejs I would not recommend anything else aside from Hapi.

So how do you use the event emitter in Hapi? Well it’s actually very simple.

Podium

The event emitter in Hapi is actually another component of the Hapi family ecosystem called Podium.

In the official github repository it states:

"podium is an event emitter with support for tags, filters, channels, event update cloning, arguments spreading, and other features useful when building large scale applications. “

Of course with Podium you can easily register an event, subscribe to an event and of course raise the event. And when using Hapi this is even easier.

Events

So lets take a look at how you can register an event in your Hapi application.

server.event('resource.created');

At this point you can easily subscribe to an event from anywhere in your code like so.

server.events.on('resource.created', async (payload) => {
    console.log(JSON.stringify(payload));
});

And of course it’s also super simple to raise the event

let payload = {
    'id': 123456,
    'name': 'chris'
};

server.events.emit('resource.created', payload);

And that’s it. It could not be simpler.

Plugins

Like I mentioned at the beginning I am a huge fan of Hapi’s plugin system. So I would like to frame the code above in different plugins, so that you can see just how simple things can be.

Let’s start with my sample plugin which represents a plugin that contains my routes and route handlers for a fictitious resource.

resourcePlugin.js

'use strict';

const resourcePlugin = {
    name: 'resourcePlugin',
    version: '0.1.0',
    register: async function (server, options) {

        // Register events exposed by this plugin
        server.event('resource.created');

        // Sample POST route
        server.route({
            method: 'POST',
            path: '/resources',
            options: {
                auth: 'some auth strategy'
                validate: {
                    // some validation rules using Joi
                }
            },
            handler: async function (request, h) {
                // Do some work here..

                // Create the payload for the event
                let payload = {
                    'id': 123456,
                    'name': 'chris'
                };

                // Raise the event
                server.events.emit('resource.created', payload);

                // Return a sample JSON response
                return h.response({ 'data': someResult }).code(201);
            }
        });

        // more routes here..
    }
};

At the same time we can create a new plugin which will handle the event that is raised when a new resource is created.

eventHandler.js

'use strict';

const eventHandlerPlugin = {
    name: 'eventHandlerPlugin',
    version: '0.1.1',
    register: async function (server, options) {

        // Handle the event
        server.events.on('resource.created', async (payload) => {
            console.log(JSON.stringify(payload));
        });

    }
};

Finally we can load our plugins in a sample Hapi server. The code below is the super simple version, just to show you how to load a plugin. For more information about Hapi and its plugins please consult the official documentation, which can be found here.

server.js

'use strict';

const Hapi = require('@hapi/hapi');

const init = async () => {

    const server = Hapi.server({
        port: 3000,
        host: 'localhost'
    });

     // load our plugins one at a time
    await server.register(require('resourcePlugin'));
    await server.register(require('eventHandlerPlugin'));

    // Start our server
    await server.start();
    console.log('Server running on %s', server.info.uri);
};

init();

That’s it, very simple yet very useful.

If this post was helpful tweet it or share it.

See Also