Evaluating Node.js Frameworks: hapi.js, Restify, and Geddy

Since my last series of posts outlining the various stages of JavaScript work and flow, I’ve been looking into a number of frameworks besides my standard go-to, Express.js, to see what other good options are out there. Hapi.js? Restify? Or Geddy? I tested out all three of them.

Here’s what I found to be each of their strengths and weaknesses.

Framework: Hapi.js

    • Strength: Simple, clean design. Performance.
    • Weakness: Not as many plugins and communities available as some of the competing frameworks.
    • Great for: Building sites and APIs with a focus on clean code and performance.

The Hapi.js framework is an interesting library that is really clean. I sat down and set up the basic example that is shown on the hapi.js site. It took a few seconds to install hapi.js and then a few seconds more to create the file, paste in the code, and execute the code.

The initial code sample on the Hapi.js site is shown below:


var Hapi = require('hapi');
// Create a server with a host and port
var server = new Hapi.Server('localhost', 8000);
// Add the route
server.route({
    method: 'GET',
    path: '/hello',
    handler: function (request, reply) {

        reply('hello world');
    }
});

// Start the server
server.start();

Most of it is relatively common. The require at the top of the code file that sets the Hapi object variable is standard. The server is set by constructing it using the Server() function on the Hapi object. Setting a base localhost variable and an initial port of 8000 all are also standard. The next code segment shows the basic setup route that serves the ‘hello world’ message to the browser via a GET request.

That simple observation really draws out how straightforward Hapi.js is in regards to making code readable. There is very little obfuscated code as there is with some of the other frameworks. The JavaScript is used in a way that is structured like many other languages without using any of the JavaScript tricks. The same, however, could be said in the opposite, depending on whether or not you’d want to use JavaScript features or stick to a more traditional structure of code on the server.

One other element that I like about Hapi.js is that the words used in the code structure  (e.g. handler, method, path and reply) are all a little more descriptive of http and Web actions than some frameworks I have used in the past. By inference this makes the code base look cleaner in its layout.

I coded up another route to provide a second example with a little more to it.


var Hapi = require('hapi');

// Create a server with a host and port
var server = new Hapi.Server('localhost', 8000);

// Add the route
server.route({
    method: 'GET',
    path: '/hello',
    handler: function (request, reply) {
        reply('hello world');
    }
});

server.route({
    method: 'POST',
    path: '/yolo',
    handler: function (request, reply) {

    	  var sampleInfo = {
    	  	author: 'Adron Hall',
    	  	book: 'Marxist Capitalist Communist Manifesto',
    	  	test: "There's a lot in this book!"
    	  };

        reply(sampleInfo);
    }
});

// Start the server
server.start();

Running the server with the node . command brought the server up. Next, I executed a curl POST request curl -X POST http://localhost:8000/yolo which provided the following results in JSON:

{"author":"Adron Hall","book":"Marxist Capitalist Communist Manifesto","test":"There's a lot in this book!"}

Such a clean way to provide a call-and-response API … I was almost blown away. There are a number of other features (including plugins like hapi-mail, routing, view rendering, and more) that are worth exploring in Hapi.js, in addition to the basic capabilities above for building APIs or serving up entire websites.

For more information about hapi.js, be sure to check out http://hapijs.com, read the API docs, and dig into the code on GitHub. To get involved directly, log into IRC #hapi, read the issues, or contribute.

My Sample Hapi.js Project: https://github.com/Adron/hapi_sample

Framework: Geddy

    • Strength: Solid and well-made framework structured on the common Model View Controller design pattern. It makes building CRUD and other more complex Web interfaces easy and quick.
    • Weakness: A little bulky for some of the newer single-page Web apps that primarily use APIs and client-side JavaScript. For those, Geddy provides a bit too much default functionality.
    • Great for: Building enterprise or startup CRUD applications with known data models in a relational database or NoSQL database like MongoDB.

The Geddy framework is focused on providing a Model View Controller (MVC) style of development pattern to follow. This differs from the other frameworks which are more focused on being a minimalist framework to start simple Web apps. Geddy, on the other hand, is built to roll MVC Web applications.

I installed Geddy with the standard sudo npm install geddy -g to get a global install of the CLI and library. Once it was installed I immediately ran the command geddy gen app geddy_sample where ‘geddy_sample’ would be the application name. One thing that is apparent upon reviewing the generated code is the similarity between Geddy and Ruby on Rails. So if you come from a Ruby on Rails background, it makes getting started with Geddy even easier.

For models, Geddy provides the scaffold command, executed as such geddy gen scaffold rank title:string description:text. The generated models are placed in the geddy_sample/app/models/* directory. Once it completes, there are models added to the project that have skeleton code as shown below.

var Rank = function () {

  this.defineProperties({
    title: {type: 'string', required: true},
    description: {type: 'text'}
  });
};

Rank = geddy.model.register('Rank', Rank);

NOTE: I removed the comments form the actual generated file for brevity.

The basic generation of the data provides a title with a string datatype and a description with a text datatype. Even though JavaScript doesn’t really have datatypes as assigned, the scaffolding that is created often has an associative check or other piece of generated code that maintains that datatype. With Geddy, the data is assumed to be coming from a database of some type like Postgres, MySQL, or other system that does have datatypes.

Once I finished testing out Geddy, I made a few comparisons. The completeness in which Geddy works is similar to a fully functional Sails.js application (for more about Sails.js, check out my write up on Node.js Frameworks and Stacks to Build Future Enterprise Apps) with a little more convention. If you’re looking for a Rails-like scaffolding setup that’s easy to get started quickly and really dive in, Geddy is a very worthwhile choice.

My Sample Geddy Project: http://blog.newrelic.com/culture/node-builds-future-enterprise/

Framework: Restify

    • Strength: Tried and true, trustworthy framework, in the sense that it is one of the earlier products set up exclusively for building APIs. The framework also has a lot of similarities with Express, which helps to build on the familiarity of its use.
    • Weakness: Follows certain practices, like shortening of object and variable names, that some may contest. Otherwise no significant weakness.
    • Great for: Building solid, trustworthy, and scalable APIs.

Getting started with Restify follows the standard Node.js approach of npm install restify. Once the base Node.js project is initialized and Restify is installed, running a simple project demo requires setting up a server.js file with the following code:

var restify = require('restify');

function respond(req, res, next) {
  res.send('hello ' + req.params.name);
  next();
}

var server = restify.createServer();
server.get('/hello/:name', respond);
server.head('/hello/:name', respond);

server.listen(8080, function() {
  console.log('%s listening at %s', server.name, server.url);
});

The basic structure of Restify is directly associative to HTTP actions and the response and request cycles. This associative nature gives it one of the easiest flows to follow out of the API frameworks, however some may find it to have wordy syntax. An example is evident in the respond function, which takes a req, res, and next continuation. Compared to a Hapi response, which is simply a handler with the reply() call, Restify can seem wordier.

Restify also handles data in real time via Socket.IO. I’ve taken the sample below directly from documentation that shows how Socket.IO is easily integrated.

var server = restify.createServer();
var io = socketio.listen(server);
server.get('/', function indexHTML(req, res, next) {
    fs.readFile(__dirname + '/index.html', function (err, data) {
        if (err) {
            next(err);
            return;
        }

        res.setHeader('Content-Type', 'text/html');
        res.writeHead(200);
        res.end(data);
        next();
});

io.sockets.on('connection', function (socket) {
    socket.emit('news', { hello: 'world' });
    socket.on('my other event', function (data) {
            console.log(data);
    });
});

server.listen(8080, function () {
    console.log('socket.io server listening at %s', server.url);
});

When making calls to the end points, you simply make the calls as if utilizing raw data. It’s fast, easily implemented, and provides streaming connectivity to the API services.

I moved next into testing some of Restify’s error handling. The first example I tried consisted of a fairly standard error catch.

if (err)
  return next(err);

However Restify provides another error trapping function called ifError() that captures errors that get thrown.

return database.get(req.params.name, function(err, user) {
    next.ifError(err);
    res.send(user);
    next();
});

The response from either of these examples is that the HTTP status codes get exposed via the ‘HttpError’ object. This helps in debugging, which brings up the next topic: DTrace.

Restify has built-in support for DTrace. I’ve never used DTrace myself, but many have a strong liking for it. If you are one of them, then this framework is definitely the choice for you. I worked out a sample to try out DTrace and made some progress. In the example provided in the documentation, several traces are set up and executed against. This feature alone is a huge advantage for performance and troubleshooting the API server.

There are many other features Restify offers, such as bundled plugins, client libraries, and more. These make great reasons to pick Restify for the next API server you put together.

My Sample Restify Project: https://github.com/Adron/restify_sample

Summary

Hapi.js, Geddy, and Restify each have their strengths and weaknesses. Hapi.js provides a great minimalistic starting point for providing a base Web app or API services. Geddy has to its credit being one of the most complete, ready-to-roll, Ruby on Rails-like frameworks to get a Web application started quickly. Restify is a solid, complete, and enterprise-ready API generation and server library. In each of these spaces the respective library excels at what it does. When you’re in the market for starting an application and not sure which library to use, these are all valid contenders.

adronhall@gmail.com'

Adron Hall is a jovial, proactive, test & code, code & test, get things done well, software architect, engineer, code monkey, coder, and distributed systems advocate. As a coder, Hall plies a polygot language path including C#, Java, JavaScript, and Erlang lately -- as well as Pascal, Basic, Visual Basic, C++, C, COBOL, RPG, CL, and others in the past. He founded Deconstructed.io with Aaron Gray, Node PDX with Troy Howard, and more startups are in the works. You can read his blog at Composite Code (http://compositecode.com). View posts by .

Interested in writing for New Relic Blog? Send us a pitch!