JSGI (JavaScript gateway interface) is the broadly adopted standard for server-side JavaScript web applications and middleware. JSGI is designed specifically for ease of use in asynchronous, evented environments, and consequently JSGI has been a perfect fit building applications on Node. JSGI-Node has existed for sometime as lightweight JSGI server/adapter for running JSGI-based applications on Node. However, “Connect” was recently released as a new alternate middleware system for Node. This spurred me to make sure JSGI-Node was optimized, and compare the Connect middleware design to JSGI.

Performance

To begin with, I did some performance comparisons. The first test is the simplest possible “hello world” application. This was run against a mock server to eliminate any overhead of HTTP parsing and isolate the test to simple request delegation. Here are the results in requests per second:

JSGI-Node: 730K/s
Connect: 204K/s

Here JSGI-Node is shown to be about 257% faster. Next, I created a stack of 9 middleware apps in front of the “hello world” app. These middleware apps do nothing but delegate to the next layer. This was designed to isolate the middleware delegation mechanism. The results are in middleware delegations per second:

JSGI-Node: 80,600K/s
Connect: 2,230K/s

Middleware delegation is over 3000% faster with JSGI than Connect! Why? JSGI is based on a simple, lightweight, pure JavaScript approach to connecting middleware. Middleware apps are simple function closures that accept another app that they can delegate to. Nothing is actually required to wire middleware together. Connect on the other hand has to go through a heavy delegation layer to wire the middleware together. Middleware delegation might not pose a significant bottleneck for simple applications, but as middleware layers accumulate, the speed of delegation becomes increasingly important.

Putting these test together, the full request delegation and middleware delegation through nine middleware layers to a simple “hello world” app results in following requests per second:

JSGI-Node: 675K/s
Connect: 112K/s

With JSGI providing about a 503% better performance with isolated request and middleware delegation.

Here are the test files.

Flexibilty

One of the powerful aspects of JSGI is that middleware is connected by simply passing apps as arguments. This means you can not only create linear stacks, but you can create rich branching tree type request routing structures. Connect on the other hand is really only designed for creating linear middleware stacks. This is useful for demonstrating simple middleware integration, but often real applications require much more sophisticated logic than these simple stacks. While Connect comes with routing middleware, it is not clear if it is possible to create middleware stacks under the different routes (especially with the same ease as JSGI).

Layer Isolation

One of the key concepts of middleware is layering. JSGI provides a simple mechanism for allow each layer to provide a controlled view of the request for the next layer and control the response from that layer. On the other hand, Connect does not provide any mechanism for wrapping and creating new request objects or handling response objects. Altering the view for the next layer means actually altering the request and response objects in place. This fundamentally breaks the layering concept of middleware because when the request object is altered, it is altered across all layers, below and above, not just for the next layer.

Ease of use

Ease of use is in the eye of the beholder, so I will just show so code comparisons. Here is a sample of how you create middleware with JSGI:

function Middleware(nextApp){
  return function(request){
    var response = nextApp(request or our own request object);
    return response or any modified response we want to return;
  };
}
// now wire it up
jsgiNode.start(Middleware(app));

And in Connect:

Middleware = {
  handle: function(req, res){
    // must modify req in place
    // modify res handlers in place as well
    next();
    // restore any res handlers that might be used lower down in the stack
  }
};
// now wire it up
var connectServer = new Server([
  {module: Middleware},
  {module: app}
]);
connectServer.listen(...);

Pintura has a wealth of examples of other middleware applications.

One complaint that has been made about JSGI is that it was not designed for specifically for Node. However, it was designed for asynchronous event-oriented architecture, which is exactly the point of Node, and so there really is no credibility to discounting JSGI for not being Node specific. It is a perfect fit for Node.

Middleware Availability

Simply take a look at the rapidly growing list of middleware modules for Node to see what is available for JSGI. JSGI is based on a collaborative effort of large number of participants in the CommonJS group. Furthermore, JSGI-Node is licensed under the Dojo foundation, which has the known for rock solid CLA-protected IP-encumberance-free liberally licensed software with a track record of being safe to use.

Now to be fair, Connect is about more than just inventing yet another middleware interface. It has some other extremely useful features including a powerful command line startup mechanism and middleware configuration techniques. In fact, Tim Caswell has actually talked about possibly including support for JSGI in Connect. This would be a great addition, and would allow Connect to actually combine the superior JSGI middleware interface with the other cool features in Connect.

The elegant design of JSGI, based on simple idiomatic JavaScript, allows for simple, intuitive middleware, with flexible connections, incredible performance, and connected to a growing ecosystem of reusable appliances.