Just a quick note to anyone who doesn't follow irc and doesn't follow me on twitter, but TJ Holowaychuk and I just released a middleware framework for node called "Connect".
It's on github under our employer's account. http://github.com/extjs/Connect
It's 100% free and MIT licensed. The goal is to provide a foundation for people to build from. We now need feedback from the framework developers in the node community to make this succeed.
There is a writeup on howtonode.org explaining it more.
-Tim Caswell
--
You received this message because you are subscribed to the Google Groups "nodejs" group.
To post to this group, send email to nod...@googlegroups.com.
To unsubscribe from this group, send email to nodejs+un...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/nodejs?hl=en.
Dear Noders,
Just a quick note to anyone who doesn't follow irc and doesn't follow me on twitter, but TJ Holowaychuk and I just released a middleware framework for node called "Connect".
It's on github under our employer's account. http://github.com/extjs/Connect
But having the same middleware spec for both blocking and non-blocking IO seems crazy to me.
I love the work the CommonJS people are doing, I'm just not convinced it's a good idea to try to abstract away stuff like http middleware to the level where it works on both node's non-blocking style and everything else's blocking style. I'm not a fan of over-abstracting.I tried the whole abstract till everything looks the same with node-persistence where I was providing a layer that sat above both SQL based databases and NOSQL based datastores using the same API. It worked, but hid and obscured a lot of the really low-level stuff that makes each platform uniquely useful.If JSGI or isaac's EJSGI is a good solution then that's fine, I just thought we needed a good node-style option into the mix. The end goal is really an easy way to share code and start writing real code.I fully support CommonJS modules when it makes sense. But having the same middleware spec for both blocking and non-blocking IO seems crazy to me.
JSGI is an attempt at a gateway interface like WSGI and Rake. Those
interfaces were initially developed to provide a sane interface
between the application layer and the server layer. The motivation
being that there are number of frameworks that should be able to run
on any compatible server. Since the gateway specification was the only
standard in the stack it was a good place to implement middleware that
could be shared between frameworks.
When i was yelling at isaacs about how eJSGI should work the first
time i met him (great introduction I'm sure) I think we both assumed
that there would be an interchangeable server component in the node
web framework stack.
Turns out, that's not the case. It's not conceivable at this time that
you would use a node web framework in production without the default
node http server, it's just too damn good.
Not needing an interchangeable server means that a gateway spec is a
bad place for interoperable middleware. I haven't spent enough time
with Connect to say that it's *the* middleware spec/implementation but
I do think that it's definitely in the right place. It's using the
standard http interfaces from node and abstracting the parts that need
to have interoperable plugins. It's a huge step in the right direction
and I'm all to happy to leave JSGI behind.
I'm sure JSGI will come back as a standard for an inter-platform web
gateway between node, narwhal, whatever other thing people use that
isn't node, but it's way too early to try and do that.
-Mikeal
Here is my perspective on Connect & JSGI.
JSGI is an attempt at a gateway interface like WSGI and Rake. Those
interfaces were initially developed to provide a sane interface
between the application layer and the server layer. The motivation
being that there are number of frameworks that should be able to run
on any compatible server. Since the gateway specification was the only
standard in the stack it was a good place to implement middleware that
could be shared between frameworks.
When i was yelling at isaacs about how eJSGI should work the first
time i met him (great introduction I'm sure) I think we both assumed
that there would be an interchangeable server component in the node
web framework stack.
Turns out, that's not the case. It's not conceivable at this time that
you would use a node web framework in production without the default
node http server, it's just too damn good.
Not needing an interchangeable server means that a gateway spec is a
bad place for interoperable middleware. I haven't spent enough time
with Connect to say that it's *the* middleware spec/implementation but
I do think that it's definitely in the right place. It's using the
standard http interfaces from node and abstracting the parts that need
to have interoperable plugins. It's a huge step in the right direction
and I'm all to happy to leave JSGI behind.
I'm sure JSGI will come back as a standard for an inter-platform web
gateway between node, narwhal, whatever other thing people use that
isn't node, but it's way too early to try and do that.
Dean, I agree that jsgi is well thought out and have no clue why the node community never picked it up, but the fact is they havent, and so I'm trying this angle. Something about jsgi just never seemed right to me personally so I started from scratch assuming nothing but node's http api.
I think Connect after some molding and prodding from the community will work great as a node only middleware stack. I don't think there is anything stopping you from using jsgi and connect at the same time either, just not sure if that's a good idea.
On Jun 7, 2010, at 11:15 PM, caster wrote:
> With the history of extjs, you wonder how it might turn to GPL
> afterwards when the community expands.
Seriously, what would be the incentive to change the license on Connect? This is a middleware framework, it's target audience is primarily framework and middleware developers. It's the api interface and the community support that has value, not the code itself. I wouldn't worry about this happening. Most of the people at the office now weren't around when the previous change happened anyway.
> On Jun 8, 8:45 am, Timothy Caswell <t...@creationix.com> wrote:
>> Dear Noders,
>>
>> Just a quick note to anyone who doesn't follow irc and doesn't follow me on twitter, but TJ Holowaychuk and I just released a middleware framework for node called "Connect".
>>
>> It's on github under our employer's account.http://github.com/extjs/Connect
>>
>> It's 100% free and MIT licensed. The goal is to provide a foundation for people to build from. We now need feedback from the framework developers in the node community to make this succeed.
>>
>> There is a writeup on howtonode.org explaining it more.
>>
>> -Tim Caswell
>
I wouldn't worry about it for now and would like to focus on just making code that works and works well.
I'm still looking for feedback on Connect itself. What works, and what doesn't?
-Tim Caswell
Yes, there is nothing stopping people from writing middleware that works on everything. If/when there are multiple middleware frameworks that are all popular then we can do this.
I wouldn't worry about it for now and would like to focus on just making code that works and works well.
I'm still looking for feedback on Connect itself. What works, and what doesn't?
I'm still looking for feedback on Connect itself. What works, and what doesn't?
On Tue, Jun 8, 2010 at 11:52 AM, Ryan Gahl <ryan...@gmail.com> wrote:On Tue, Jun 8, 2010 at 9:26 AM, Timothy Caswell <t...@creationix.com> wrote:I'm still looking for feedback on Connect itself. What works, and what doesn't?I'm planning to include a Connect-able interface in my WIP framework port... so when I get that far I'll let you know. I can say just from looking at it that I find the notion of .next() interesting, and may actually fork the code to see if that can be carried farther (using an FSM structure to route traffic to various layers of the app-stack as needed).I'm also curious about the .next() thing. To me it's a little surprising -- why is it there? What's the distinction between calling it and just returning undefined? It seems like there has to be some kind of manager shuttling your request objects to the various components (otherwise you'd be calling .next(request) like in JSGI). So what's it's function.
Also, what's the best forum for this discussion? Should we be pounding the node list with Connect-specific questions?
A *lot* of people got burned (rightly or wrongly) by that particular
switcharoo, and people have long memories :( It definitely is
something that puts me off about connect ... which is a shame as
technically it looks cool ! :)
-cj.
An example use case is:
GET request -> Database query -> HTML template system -> gzip -> Response.
In the above system what you really want is a chain of streams so that
the database query returns some event emitter for "row" which makes a
call to the template engine to render another for that row which emits
a "data" event of rendered HTML which the gzipper compresses and emits
"data" which is written to the response object.
When the response write returns "false" you also want a pause event to
work it's way back up to the database query, same with the drain
events -> resume().
It doesn't matter how fast node is if we continue to wait on entire
remote IO queries to finish before we start returning them to the
Browser page load times will still bottleneck on waiting for the
queries to finish and buffering all of this in to memory means we
can't have nearly as many concurrent connections open before we run
out of memory. The above example should start rendering in the browser
before a large database query is even finished.
-Mikeal
So, what I said, and I still think this is true, no middelware/plugin
system should buffer the data from any stream and should encourage the
use of "chained" streams.
An example use case is:
GET request -> Database query -> HTML template system -> gzip -> Response.
In the above system what you really want is a chain of streams so that
the database query returns some event emitter for "row" which makes a
call to the template engine to render another for that row which emits
a "data" event of rendered HTML which the gzipper compresses and emits
"data" which is written to the response object.
When the response write returns "false" you also want a pause event to
work it's way back up to the database query, same with the drain
events -> resume().
It doesn't matter how fast node is if we continue to wait on entire
remote IO queries to finish before we start returning them to the
Browser page load times will still bottleneck on waiting for the
queries to finish and buffering all of this in to memory means we
can't have nearly as many concurrent connections open before we run
out of memory. The above example should start rendering in the browser
before a large database query is even finished.
I hope you're
not put off by what happened a long time ago
This is basically how WSGI works and it's terrible. For one, if you
don't have data to return yet you have to check some status and return
'' everytime the iterator is called. There isn't any "drain'
equivalent that can propagate up the stack for slow clients, which
means you're still going to be buffering the writes.
We have a way to deal with all this in node, Streams. We should use them.
-Mikeal
I'm really hesitant to add any abstraction above node itself unless it makes a huge difference. I think streams might be a good place where it's worth it though.
Yes, please keep the discussion here. I'd prefer we not get fractured,
this is all interrelated.
I just don't think it's enough to only have a forEach.
This is basically how WSGI works and it's terrible. For one, if you
don't have data to return yet you have to check some status and return
'' everytime the iterator is called. There isn't any "drain'
equivalent that can propagate up the stack for slow clients, which
means you're still going to be buffering the writes.
We have a way to deal with all this in node, Streams. We should use them.
Why shouldn't pause/resume/drain be part of the standard interface? If
it's not then the interface encourages buffering.
I do understand what you *can* do with forEach but it seems like the
JSGI usage of forEach is bending over backwards to provide for a
simpler blocking interface without requiring blocking by allowing a
forEachable object. All the forEach voodoo aside, actually building
stuff on this this level of abstraction is a pain in the ass and the
harder it is the more people will do things the *easier* way (which is
to buffer).
In my opinion, we need to create a good, if not great, plugin
interface that discourages blocking and buffering. We can worry about
interop with other platforms later once we have some solid for node.
There is nothing in the Stream interface that can't be implemented in
other platforms like narwhal it just *doesn't* allow for a blocking
interface.
-Mikeal
All the forEach voodoo aside, actually building
stuff on this this level of abstraction is a pain in the ass and the
harder it is the more people will do things the *easier* way (which is
to buffer).
In my opinion, we need to create a good, if not great, plugin
interface that discourages blocking and buffering. We can worry about
interop with other platforms later once we have some solid for node.
There is nothing in the Stream interface that can't be implemented in
other platforms like narwhal it just *doesn't* allow for a blocking
interface.
-Mikeal
Dean I remember lurking on the commonjs mailing list when JSGI was being solidified, and I followed all of the logic that led to forEachables. But at that time it was still pretty abstract in my head, particularly in the case of using it in an async fashion. Now that I have a more concrete mental model of asynchronous http because of node, I want to revisit it. Your explanation is intriguing. Thanks for the run down.I'm of two minds about this in terms of the API though. One the one hand it is nice that JSGI requires only javascript constructs and you can work with streams as if they were arrays. Node requires you to wrap your head around the stream api and learn to use it effectively. It becomes a critical extension to the language/platform when you're using node. But that's not different than what frameworks like django makes you learn in order to use them. Nobody really deals with raw WSGI so I can't say what the strictly analogous comparison is.
On the other hand, I think the Stream api gives you more flexibility for creating interfaces that are more descriptive. If you're just doing body.forEach, there's really no context for what's coming out of there. It could be random chunks, it could be whole db rows, it could be json objects, it could be one item with an entire response body.But you can set your stream emitter interface to make the output explicit:var resultStream = db.query(...);resultStream.addListener('result_row', function(row) { ...});
exports.onResponse = function (obj, in, out) {var accept = obj.req.headers["accept-encoding"];var type = obj.res.headers["Content-Type"];if (!(obj.res.code === 200 && accept && accept.indexOf('gzip') >= 0&& type && (/(text|javascript)/).test(type))) {var gzip = child_process.spawn("gzip", ["-9"]);pump(in, gzip.stdin);pump(gzip.stdout, out);} else {pump(in, out);}};