JSGI Middleware

41 views
Skip to first unread message

Nathan Stott

unread,
Dec 27, 2011, 5:17:00 PM12/27/11
to CommonJS
I believe the function signature for JSGI middleware is suboptimal.

Currently we have 

function(nextApp) {
  return function(req) { 
    ...
  }
}

I believe we should instead have

function(req, nextApp) {
  ...
}

This is easier to grok for the average programmer.  It permits rearranging middlware more easily rather than having to construct a new piece of middleware everytime you want to call something
different after it. I am running into a need to do the latter in order to provide a good user experience in Bogart. Anytime that you have a function that intends to act on an array of middleware to combine them in an interesting way, this would be a big win.

The final biggest win is that this unifies the concept of 'JSGI App' and 'JSGI Middleware'.  If it is an App, just leave off the nextApp parameter.

Christoph Dorn

unread,
Dec 28, 2011, 2:54:26 PM12/28/11
to comm...@googlegroups.com

I agree. The current signature can lead to a lot of confusion fast. We
also do not need to enforce the init/request split from a lifecycle
perspective as CommonJS Modules get initialized only once.

One area the simplified signature does not address is the passing of
options to the middleware for the init cycle. While I am using this
feature I do not see it as essential. Most options are or can be made
global to the stack and can be passed as part of the REQ/ENV. If the
middleware must initialize based on options from REQ/ENV it ought to
find common denominators that can be used to cache an initialized
request handler.

Alternatively one may make a call to the middleware module prior to
linking it into the stack in order to set options global to the module.

So overall I am +1 for this change to most importantly simplify the
signature and allow for easier comprehension.

Christoph

Nathan Stott

unread,
Dec 28, 2011, 3:06:44 PM12/28/11
to comm...@googlegroups.com
I agree with your comments about option initialization.

I think this change will go a long way towards making JSGI more friendly for non-elite programmers.



Christoph

--
You received this message because you are subscribed to the Google Groups "CommonJS" group.
To post to this group, send email to comm...@googlegroups.com.
To unsubscribe from this group, send email to commonjs+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/commonjs?hl=en.


Kris Kowal

unread,
Dec 28, 2011, 3:17:18 PM12/28/11
to comm...@googlegroups.com
I am not looking forward to rewriting the JSGI stack. This would also
probably impact performance, since configuration management would
occur at every request instead of at initialization. It does have the
benefit of making it possible to use a piece of middleware at multiple
branches of a route. I do not think that it is particularly elitist to
push JavaScripters to learn how to use closures.

Kris Kowal

Nathan Stott

unread,
Dec 28, 2011, 3:57:40 PM12/28/11
to comm...@googlegroups.com
As I stated in my first email, another of the major benefits is unifying the 'app' and 'middleware' concept.

I want to have something like this:

router.get('/', function(req, nextApp) {
  // do stuff
  return nextApp(req);
}, function(req, nextApp) {
  // do stuff
  return nextApp(req);
}, function(req) {
  return {
    status: 200,
    ....
  }
});

// How this would look currently:

route.get('/', function(nextApp) {
  return function(req) {
    // do stuff
    return nextApp(req);
  }
}, function(nextApp) {
  return function(req) {
    // do stuff
    return nextApp(req);
  }
},  function(nextApp) {
  // nextApp will always be undefined here
  return function(req) {
    return {
      status: 200
      ...
    }
  }
});

The biggest problem is that a 'combined' solution of implementing this type of pattern with current JSGI where you can have either a JSGI App or a JSGI Middleware passed is that you cannot know from a function whether it is middleware or an app.  There is no way to determine if something wants to be a function(req) {} or a function(nextApp) { return function(req) }, there's no way to be compatible with both without doing something smelly to the new pattern like adding a 'isNewMiddleware' property to the prototype or something equally awful.

I'd be surprised if there were performance problems resulting from anything other than poorly written code. The actual pattern would have one less closure which should theoretically make it more performant if we are microoptimizing.

I'm not going to call you an elitist for wanting JavaScript programmers to learn about closures.  I think most of them understand closures fairly well.  However, from my anecdotal experience with my employees and my perception of the community at large, the current JSGI pattern is confusing, hard to use, and a big turn-off compared to using a middleware framework like Connect.

--
You received this message because you are subscribed to the Google Groups "CommonJS" group.
To post to this group, send email to comm...@googlegroups.com.
To unsubscribe from this group, send email to commonjs+u...@googlegroups.com.

Christoph Dorn

unread,
Dec 28, 2011, 3:58:07 PM12/28/11
to comm...@googlegroups.com
Kris Kowal wrote:
> I am not looking forward to rewriting the JSGI stack. This would also
> probably impact performance, since configuration management would
> occur at every request instead of at initialization. It does have the

I venture to say that configuration management is an aspect that ought
to be unrelated to the JSGI interface.

The JSGI interface should define only the minimal method signature and
the properties on the request and response objects.

Configuration management is very much dependent on the environment the
middleware app runs in and on the preferences of the developer writing
the middleware app (very little consistency in naming conventions). It
is also static across multiple requests. It comes into play only during
the construction of the JSGI stack which makes it a bootstrap issue.

Current JSGI stack construction with options is messy without helpers
and hard to follow when scanning code.

I think we would be better off if we initialized middleware apps in a
flat sequence one after the other and then assembled them into the stack
we need in a second step.

I have the need to configure many of my modules, not just middleware
apps. Maybe module-level config management should get its own spec. By
separating config management and making it more parseable it can be
dealt with during build time when optimizing for environments removing
it from the runtime completely.


> benefit of making it possible to use a piece of middleware at multiple
> branches of a route. I do not think that it is particularly elitist to
> push JavaScripters to learn how to use closures.

For some reason this particular closure seems harder to understand. I
had a good understanding of closures yet the JSGI interface took me more
time to remember and understand. Maybe that is an indicator that it
combines too much? We are not even talking about streaming or returning
promises.

Christoph

Nathan Stott

unread,
Dec 28, 2011, 4:41:11 PM12/28/11
to comm...@googlegroups.com

benefit of making it possible to use a piece of middleware at multiple
branches of a route. I do not think that it is particularly elitist to
push JavaScripters to learn how to use closures.

For some reason this particular closure seems harder to understand. I had a good understanding of closures yet the JSGI interface took me more time to remember and understand. Maybe that is an indicator that it combines too much? We are not even talking about streaming or returning promises.


It's my belief that this is because of the difference between middleware and app in JSGI, a difference I think we'd be wise to do away with.
The reason I make this proposal is that I really want to see JSGI compete with Connect in the Node.JS sphere as I like JSGI a lot more.  I believe this one change would go a long way in making the fight for mindshare easier.  We're already asking people to learn a lot as Christoph points out so aptly in his message.

Christoph Dorn

unread,
Dec 29, 2011, 9:46:56 PM12/29/11
to comm...@googlegroups.com
FYI, here is a crude Connect middleware that provides a JSGI interface: https://github.com/pinf/server-js/blob/master/lib/vendor/connect/middleware/jsgi.js

Christoph

Reply all
Reply to author
Forward
0 new messages