How to create reusable modules in Express 4.x by using events for loose coupling.
Wheew… long title what?
Ok, so what’s this all about then? If you’ve built Express based applications for a while, you’ll soon find that there are certain ‘functionalities’ or components which repeat across the apps you build. A good example is handling user authentication. How do you make your user authentication module reusable across your projects?
The ‘problem’ tends to be tied to the ‘pattern’ in which route handlers are almost inevitably intertwined with rendering of the view — essentially route handlers become ‘Controllers’ since they not only respond to route patterns but also handle rendering of the templates.
The good news is that we can leverage a fundamental construct of Node.js (which Express also leverages) to decouple various components of our apps and thus allow these components to be reusable across multiple projects. The construct we are interested in is the ‘EventEmitter’ object of Node.js which is a fundamental object from which many Node and Node based constructs derive (i.e. they inherit from EventEmitter).
As usuall, the code for this article is available at https://github.com/oakinogundeji/express-events
OVERVIEW OF EVENTEMITTER
The Node EventEmitter is an implementation of the ‘Observer’ pattern (commonly encountered as the ‘PubSub’ implementation) which allows objects to publish ‘custom events’ based on user determined triggers, these events can be listened for and handled by interested portions of our code and thus the emitter and responder need not expressly ‘know’ about one another — this pattern is a key to developing loosely coupled apps.
In exploring how we can use EventEmitter in Express, we will build a simple application which allows authenticated users to log in and view their info on a ‘dashboard’, along the way we will build an ‘authentication’ module which we can comfortably reuse across our projects since user authentication is such a fundamental feature of any non trivial app.
It’s only right that we understand what we’re working towards, the following screenshots present our goal.
Since we’re focusing specifically on how we can use events to decouple our app, we won’t exhaustively examine every part of our application, rather we’ll focus on the most interesting portions of our code. Those portions are app.js (the main Express app), routes.js (the handler for the root), auth.js (the reusable authentication module) and index.js (the ‘view rendering’ module).
Lets’ begin with app.js, the structure for a more modular app built around events is slightly different to what we’re used to. This is because app.js not only serves as the entry point/bootstrapper, but it also serves as the ‘trunk’ of the codebase to which all the components are connected and from which the ‘dependencies’ which the reusable components need to fully serve the app are derived (.i.e. we implement the dependency injection pattern).
The reason for this structure is because the object exposed by Express (.i.e. the object traditionally identified as ‘app’) extends the base Node.js EventEmitter class, in other words, ‘app’ is an event emitter with all the ‘goodies’ that implies!
If you’ve followed my coding style in previous articles, you’ll know that i like to ‘declare’ dependencies where they are needed, in other words, i try to follow a clearly modularized pattern in my projects. Thus line 8 should be an obvious departure from my previous coding style. Rather than pulling in the passport module in the ‘router’, we’re using it within the base app. This is necessary to implement the ‘dependency injection’ pattern we will see shortly.
The next interesting portion of code are lines 32&33. On line 32, we implement the ‘dependency injection’ pattern by ‘injecting’ the passport object from line 8, into the function returned by the module which we have labelled ‘auth’ (more on this shortly).
On line 33 we declare a ‘renderHandlers’ object which we will examine more deeply shortly.
The next interesting portions of code are lines 85&86. On line 85, we map the ‘public’ directory which holds our static assets to the ‘express.static’ middleware and we mount this on ‘/’. While this ‘mount point’ is not explicitly declared, this is the default behaviour with Express. This operation is saying ‘any calls for static assets (css, js, imgs, fonts etc) which come from any route derived from “/” should be satisfied by accessing the path passed to express.static (in this case “__dirname/public”)’.
On line 86, we do something you may not be used to, we map a ‘public’ directory to ‘express.static’ and mount it on the ‘/auth’ mount point. Close examination to the path passed to express.static will reveal that it’s the same path as for line 85, this means that we are essentially ensuring that any calls for static assets generated though routes derived from ‘/auth’ will also be satisfied by the same ‘public’ directory. This is essential! Otherwise what would happen is that when we try to render templates from routes derived from ‘/auth’ it would look for something like ‘/auth/css/styles.css’ rather than ‘css/styles.css’. (Unfortunately i can’t dive deep into the workings of express.static and res.render etc since the focus of this article is something else, but you may leave a comment or drop a line if you need clarification).
On lines 92&93 we mount router components to different mount points ‘/’ for the base router and ‘/auth’ for the authentication module.
Now to the really interesting bits, lines 98–103. We see a pattern we should be familiar with from jQuery and front end work, but maybe not so familiar with in Express. We are defining a range of ‘event handlers’ to handle custom events intercepted by ‘app’. As you may notice, every handler is a method of the ‘renderHandlers’ object (more on that later).
After creating a custom error handler we export the module.
The next module we will examine is routes.js, while not the primary module of interest, it does introduce the pattern we will explore more deeply in a bit.
The most interesting portions of this module are on lines 25–27. On line 25 everything appears as usual, the ‘root’ route is declared and the handler begins, but line 26 marks a deviation from the norm! Rather than render a view, send a file or directly handle the request, the handler does something else… it calls ‘req.app’, emits an event and passes on the ‘req, and res’ objects which the handler intercepted!
What is ‘req.app’? In Express, req.app and res.app are a pattern which allows the underlying ‘app’ object to be exposed to the req/res objects from a request-response cycle. Thus, rather than passing round a reference to ‘app’, or creating a ‘global’ object, req.app/res.app is a very clean way to tie the req/res objects to ‘app’. What’s the difference between req.app and res.app? Nothing! Use whichever you prefer, i use req.app because it makes it clear (at least to me) that the incoming request hasn’t been responded to yet.
The ‘getRoot’ custom event is triggered on the underlying ‘app’ object and the req/res objects bound to that particular cycle are passed along as reference. So where is this event handled? Line 98 of app.js.
On line 98, the ‘getRoot’ event is handled by the ‘renderHandlers.root’ handler. We’ll hold off for a while before examining the inner workings of his handler and it’s siblings. But note that this pattern already gives us a huge advantage — we can right modular, compartmentalized code without creating globals simply by referncing the undelying ’app’ object via either req.app or res.app. This is really important.
This is the ‘most important’ module in this app simply because it demonstrates how we can create reusable modules for our projects.
You’ll immediately notice that rather than returning an object, this module returns a function! This is the key to the ‘dependency injection’ pattern. The function takes the passport object from line 8 of app.js as it’s sole argument. This means that ‘passport’ objects with different configurations can be passed to the module and it will still function as expected! That’s very powerful!
Line 39 begins the portions we’re particularly interested in. Recollect that on line 93 of app.js, this module is mounted to the ‘/auth’ mount point, this means that all routes defined within this module are automatically prefixed with ‘/auth’ e.g. line 39 ‘/login’ is actually ‘/auth/login’.
You’ll notice a recurring pattern throughout this module, as we noticed in routes.js, every route handler will cause the underlying app to emit an event and pass along data rather than directly addressing the request from the client. Also, in cases where redirection is required e.g. line 56, the full route is referenced e.g.’/auth/dashboard’ rather than ‘/dashboard’. This is because a redirect must be passed the ‘absolute’ path rather than a ‘relative’ path.
I’m confident that by now you’ve guessed that the emitted events are all handled in app.js specifically between lines 99 and 103.
Another interesting portion of code is between lines 83 and 146. This portion represents the handler for ‘/auth/dashboard’ — after doing a bunch of stuff, it too causes the underlying app to emit an event rather than directly handling the request.
Finally on line 170, the fully configured ‘router’ object is returned as the effective value of ‘module.exports’.
Question: Why are we implementing this pattern using the ‘router’ mini app?
Answer: In Express, the router mini app is the only other builtin way, apart from the actual ‘app’ object to access the EventEmitter functionality of Express. Other means are possible, but none is as clean and elegant as this.
Great, that brings us to the ‘final’ piece of the puzzle — view rendering and response handling!
The custom event handlers in app.js are simply a group of functions which the underlying ‘app’ uses to render views in response to the emitted custom events which the app intercepts. In order to provide the correct response to a particular request from the client, the handler must have access to the response object which is the other ‘half’ of the request-response cycle. This is why regardless of whether any ‘data’ is available, the req and res objects for a particular route are always passed to ‘app’ along with the custom event.
If you’re really new to Express, Passport and Authentication, you may want to review my previous articles for solid background on these technologies.
As usual please leave your comments or drop me a line. Thanks for reading.