Skip to content


Subversion checkout URL

You can clone with
Download ZIP


Should Response always be a promise? #1

tlrobinson opened this Issue · 12 comments

3 participants



  • Simplifies middleware by reducing need for promise library.

Allows middleware to use then directly:

return app(request).then(function(response) {
    // ...

vs. using a promise library, e.x. Q.when:

return Q.when(app(request), function(response) {
// ...


  • Makes synchronous (and "hello world") responses more complex by forcing them to create a new promise.


  • Q-HTTP supports returning object directly.

I personally really like the idea of making responses promises. In addition to the pros and cons you've mentioned:


  • The signature for apps is simplified (when compared with the function (env, callback) {} signature that strata uses). One argument + a meaningful return value is better than a callback.


  • Promises are a foreign concept to many node users. This essentially boils down to education/evangelism, IMO. Not too big of a problem, but will definitely raise some eyebrows.

Yes, the "hello world" will be a bit uglier. We could possibly work around this issue with some syntactic sugar, e.g.

var Response = require('mach').Response;
function (env) {
  return Response(200, {}, 'hello world');

In this case Response would be a new-neutral constructor for a promise.


@mjijackson I had actually assumed we already agreed on using promises to support async responses. This issue was meant to discuss whether or not the returned object should always be a promise, or if we can sometimes return a response object directly.


We can go two different ways on this, I think.

1) Force all responses to be promises. No plain objects allowed. Assuming that all apps are really just functions that can be invoked any number of ways, this simplifies the API for callers so they always know what to expect. Callers should not need to check the type of an app's return value. We could possibly use a Response object or something similar to smooth out the "hello world" example.

2) Provide a function, it could be, that is always used for calling apps. This function would be used internally by a Server and all middleware to call downstream apps. It would then take care of coercing the return value to a promise if it isn't already.

A no-op middleware might look like this:

function (app) {
  return function (env) {
    return, env).then(function (res) {
      // res is a promise

This would allow the "hello world" example to be extremely simple. In fact, we could go so far as to let the user return a simple string from an app.

function (env) {
  return "Hello world!";

Since we always control how apps are called, we can accomodate a wider range of return values.


The idea is intriguing. It could be pretty powerful. You could even solve the header case-sensitivity issue by lowercasing all keys. Of course you'd need to be careful about performance.

However, is counter to the goal of being a middleware interface over an application framework. But it's an attractive compromise. Being able to return a string makes for a sexy "hello world"

@kriskowal, what do you think?


I do think that we can mandate that the return value of an application be one specific type of object with a rich interface, if we also mandate that there be an adapter that coerces all of the shorthands to that type. The simplest form would be:

function adapter(app) {
    return function (request) {
        return coerceResponse(app(coerceRequest(request)))
        .then(function (response) {

I think is a bit cleaner since its less nested, plus it would let you do stuff on the request side as well.

I could even envision a framework injecting a convienence object that lets you do things like this.status(200); this.header(..., ...) and then constructing a proper Mach response or something.


I committed a very rough prototype playing around with these ideas and more: 6419751


@tlrobinson I really like where we're going with this. You're right that it does tend to cater more towards app developers, but the abstraction is so useful in this case that I'm willing to make the trade-off. I just committed some small modifications to your prototype that makes two small changes:

  • Introduces a Request constructor that is used as an abstraction on top of node requests. This has been very useful in strata as node's core API has changed. It also isolates the application from the original request object, allowing us to do useful things like buffer the input stream, etc.
  • Uses Request#call to call downstream apps. This lets devs use an object they already have in scope instead of needing to require the mach module in every middleware just so they can use

@mjijackson For sure, I was just using Node's request object to get started.

@kriskowal What are your thoughts so far?

FYI I was just using CoffeeScript for that example because it looked really pretty with the shorthand responses.


I was also playing around with the idea of making #call extensible by middleware somehow.

i.e. by default it would do the simple coercions (non-promises -> promises, string content -> stream) but middleware could append "filters" to the request that get executed before or after each invocation of #call.

Not sure if this is useful enough to be worth the added complexity.


Currently the code accepts either a direct response object or a promise for one. This approach has proven to be pretty flexible up to this point. If you're ok with it @tlrobinson I'd like to move forward and close this issue. If you'd like to discuss before/after filters or something similar, let's put that in a separate issue.

P.S. Sorry to bring up these old issues again, but I'd like to get things ready for a stable release.


Closing this issue. Please feel free to re-open if you'd like to discuss further.

@mjackson mjackson closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.