From web application design and development point of view, how do Express and Hapi compare to each other? For basic examples they seem similar, however I'm interested to learn more about key differences in overall application structure.
For example, as far as I have learned, Hapi uses a different routing mechanism which does not take registration order into account, can do faster lookups, but is limited comparing to Express. Are there other important differences?
There is also an article about choosing Hapi (over Express) for developing the new npmjs.com website, this article states that "Hapi’s plugin system means that we can isolate different facets and services of the application in ways that would allow for microservices in the future. Express, on the other hand, requires a bit more configuration to get the same functionality", what does it exactly mean?
This is a big question and requires a long answer to be complete, so I'll just address a subset of the most important differences. Apologies that it's still a lengthy answer.
How are they similar?
You're absolutely right when you say:
For basic examples they seem similar
Both frameworks are solving the same basic problem: Providing a convenient API for building HTTP servers in node. That is to say, more convenient than using the lower-level native http
module alone. The http
module can do everything we want but it's tedious to write applications with.
To achieve this, they both use concepts that have been around in high level web frameworks for a long time: routing, handlers, plugins, authentication modules. They might not have always had the same names but they're roughly equivalent.
Most of the basic examples look something like this:
- Create a route
- Run a function when the route is requested, preparing the response
- Respond to the request
Express:
app.get('/', function (req, res) {
getSomeValue(function (obj) {
res.json({an: 'object'});
});
});
hapi:
server.route({
method: 'GET',
path: '/',
handler: function (request, reply) {
getSomeValue(function (obj) {
reply(obj);
});
}
});
The difference is not exactly groundbreaking here right? So why choose one over the other?
How are they different?
The simple answer is hapi is a lot more and it does a lot more out-of-the-box. That might not be clear when you just look at the simple example from above. In fact, this is intentional. The simple cases are kept simple. So let's examine some of the big differences:
Philosophy
Express is intended to be very minimal. By giving you a small API with just a thin dusting on top of http
, you're still very much on your own in terms of adding additional functionality. If you want to read the body of an incoming request (quite a common task), you need to install a separate module. If you're expecting various content-types to be sent to that route, you also need to check the Content-type
header to check which it is and parse it accordingly (form-data vs JSON vs multi-part for example), often using separate modules.
hapi has a rich feature set, often exposed through configuration options, rather than requiring code to be written. For instance, if we want to make sure a request body (payload) is fully read into memory and appropriately parsed (automatically based on content-type) before the handler is ran, it's just a simple option:
server.route({
config: {
payload: {
output: 'data',
parse: true
}
},
method: 'GET',
path: '/',
handler: function (request, reply) {
reply(request.payload);
}
});
Features
You only need to compare the API documentation on both projects to see that hapi offers a bigger feature set.
hapi includes some of the following features built-in that Express does not (as far as I know):
- Input and response validation (through Joi)
- Server-side caching with multiple storage options (mongo, S3, redis, riak), that can be enabled with a few lines of configuration
- Cookie-parsing
- Sessions
- File uploading/multipart parsing
- CORS support
- Logging
Extensibility & modularity
hapi and Express go about extensibility in quite a different way. With Express, you have middleware functions. Middleware functions are kind of like filters that you stack up and all requests run through them before hitting your handler.
hapi has the request lifecycle and offers extension points, which are comparable to middleware functions but exist a several defined points in the request lifecycle.
One of the reasons that Walmart built hapi and stopped using Express was a frustration with how difficult it was to split a Express app into separate parts, and have different team members work safely on their chunk. For this reason they created the plugin system in hapi.
A plugin is like a sub-application, you can do everything you can in a hapi app, add routes, extensions points etc. In a plugin you can be sure that you're not breaking another part of the application, because the order of registrations for routes doesn't matter and you can't create conflicting routes. You can then combine this plugins into a server and deploy it.
Ecosystem
Because Express gives you so little out of the box, you need to look outside when you need to add anything to your project. A lot of the times when working with hapi, the feature that you need is either built-in or there's a module created by the core team.
Minimal sounds great. But if you're building a serious production app, the chances are you're going to need all of this stuff eventually.
Security
hapi was designed by the team at Walmart to run Black Friday traffic so security and stability have always been a top concern. For this reason the framework does a lot of things extra such as limiting incoming payload size to prevent exhausting your process memory. It also has options for things like max event loop delay, max RSS memory used and max size of the v8 heap, beyond which your server will respond with a 503 timeout rather than just crashing.
Summary
Evaluate them both yourself. Think about your needs and which of the two addresses your biggest concerns. Have a dip in the two communities (IRC, Gitter, Github), see which you prefer. Don't just take my word. And happy hacking!
DISCLAIMER: I am biased as the author of a book on hapi and the above is largely my personal opinion.
My organization is going with Hapi. This is why we like it.
Hapi is:
- Backed by major corps. This means the community support will be strong, and there for you throughout future releases. It's easy to find passionate Hapi people, and there are good tutorials out there (though not as numerous and sprawling as ExpressJs tutorials). As of this post date npm and Walmart use Hapi.
- It can facilitate the work of distributed teams working on various parts of the backend services without having to have comprehensive knowledge of the rest of the API surface (Hapi's plugins architecture is the epitome of this quality).
- Let the framework do what a framework is supposed to: configure things. After that the framework should be invisible and allow devs to focus their real creative energy on building out business logic. After using Hapi for a year, I definitely feel Hapi accomplishes this. I... feel happy!
If you want to hear directly from Eran Hammer (Hapi's lead)
Over the past four years hapi grew to be the framework of choice for many projects, big or small. What makes hapi unique is its ability to scale to large deployments and large teams. As a project grows, so does its complexity – engineering complexity and process complexity. hapi’s architecture and philosophy handles the increased complexity without the need to constantly refactor the code [read more]
Getting started with Hapi won't be as easy as ExpressJs because Hapi doesn't have the same "star power"... but once you feel comfortable you'll get A LOT of mileage. Took me about ~2 months as a new hacker who irresponsibly used ExpressJs for a few years. If you're a seasoned backend developer you'll know how to read the docs, and you probably won't even notice this.
Areas the Hapi documentation can improve on:
- how to authenticate users and create sessions
- handling Cross-Origin-Requests (CORS)
- uploading files (multipart, chunked)
I think authentication would be the most challenging part of it because you have to decide on what kinda auth strategy to use (Basic Authentication, Cookies, JWT Tokens, OAuth). Though it's technically not Hapi's problem that the sessions/authentication landscape is so fragmented... but I do wish that they provided some hand-holding for this. It would greatly increase developer happiness.
The remaining two aren't actually that difficult, the docs could just be written slightly better.
Quick Facts about Hapi Or Why Hapi JS ?
Hapi is configuration-centric
It has authentication and authorization built into the framework
It was released in a battle-tested atmosphere and has really proven its worth
All the modules have 100% test coverage
It registers the highest level of abstraction away from core HTTP
Easily compassable via the plugin architecture
Hapi is a better choice performance wise
Hapi uses a different routing mechanism, which can do faster lookups, and take registration order into account.
Nevertheless, it is quite limited when compared to Express. And thanks to the Hapi plugin system, it is possible
to isolate the different facets and services that would help the application in many ways in the future.
Usage
Hapi is the most preferred framework when compared to Express. Hapi is used mainly for large-scale enterprise applications.
A couple of reasons why developers do not choose Express when creating enterprise applications are:
Routes are harder to compose in Express
Middleware gets in the way most of the time; each time you are defining the routes, you have to write as many numbers of codes.
Hapi would be the best choice for a developer looking to build RESTful API. Hapi has micro-service architecture and it is also possible to transfer the control from one handler to another based on certain parameters. With the Hapi plugin, you can enjoy a
greater level of abstraction around HTTP because you can divvy up the business logic into pieces easily manageable.
Another huge advantage with Hapi is that it provides detailed error messages when you misconfigure. Hapi also lets you configure your file upload size by default. If the maximum upload size is limited, you can send an error message to the user conveying that the file size is too large. This would protect your server from crashing because the file uploads will no longer try to buffer a whole file.
Whatever you can achieve using express can also be easily achieved using hapi.js.
Hapi.js is very stylish and organizes the code very well. If you see how it does routing and puts the core logic in controllers
you will defiantly be going to love it.
Hapi.js officially provide several plugins exclusively for hapi.js ranges from token based auth to session management and many more,
which is an ad on. It doesn't mean the traditional npm can't be used, all of them are supported by hapi.js
If you code in hapi.js, a code would be very maintainable.
Just another point to add, Hapi has started supporting 'http2' calls from version 16 onwards (if I am not wrong ). However, express is yet to support 'http2' module directly till express 4. Although they have released the feature in the alpha version of express 5.