0

So. I'm experiencing some quirks when attempting to implement some basic middleware for a Restify.js application I'm building with specific regard to next() and promise callbacks.

To express the problem in a generic form:

  var server = restify.createServer({
    name: config.name
  });

Promise resolves:

  server.use(function checkAcl(req, res, next) {
    // Promise is resolved
    var promise = function () {
      var deferred = require('q').defer();
      deferred.resolve();
      return deferred.promise;
    }

    promise()
      .then(function () {
        next(); // doesn't get 'called', no response sent, connection eventually times out
      }, function () {
        res.send(new restify.NotAuthorizedError());
      });
  });
  server.use(restify.bodyParser());

  ...

Promise is rejected

  server.use(function checkAcl(req, res, next) {
    // Promise is rejected
    var promise = function () {
      var deferred = require('q').defer();
      deferred.reject();
      return deferred.promise;
    }

    promise()
      .then(function () {
        next(); 
      }, function () {
        res.send(new restify.NotAuthorizedError()); // this works fine
      });
    }
  });

  server.use(restify.bodyParser());      

  ...

Am I doing anything obviously wrong? Any insight? It certainly seems to been related to the promise callbacks, are they somehow suppressing the call to next()?

Matt Richards
  • 1,477
  • 2
  • 14
  • 21
  • Which of your `console.log`s happen? – Domenic Jun 13 '13 at 16:14
  • ok, so in the example above. ACL passes `(allowed === true)` so to answer your question directly: AuthToken Verified, Found User, ACL Passed – Matt Richards Jun 13 '13 at 16:18
  • updated the question with a more generic representation of the problem (see bottom). – Matt Richards Jun 13 '13 at 16:28
  • what if you replace the promise code with `setTimeout(function () { next(); }, 0);`? Also try just calling `next()` directly. – Domenic Jun 13 '13 at 17:12
  • BTW you can replace those lines with `var promise = Q.resolve()` and `var promise = Q.reject()` then replace `promise()` with `promise`. – Domenic Jun 13 '13 at 17:12
  • The problem seems related to my use of ` server.use(restify.bodyParser());` (which I had neglected to mention). Changing the order of the `server.use()` declarations seems to have solved the problem. – Matt Richards Jun 13 '13 at 17:18

1 Answers1

0

Adding the restify.bodyParser() middleware BEFORE the custom middleware resolves the issue.

n.b:

  // Add bodyParser() to the stack before the custom middleware
  server.use(restify.bodyParser()); 

  server.use(function checkAcl(req, res, next) {
    // Promise is resolved
    var promise = function () {
      var deferred = require('q').defer();
      deferred.resolve();
      return deferred.promise;
    }

    promise()
      .then(function () {
        next(); // next() now behaves as expected.
      }, function () {
        res.send(new restify.NotAuthorizedError());
      });
  });
  ...

Further to that, I eventually happened upon this Github issue describing the issue along with another possible solution if the order of your middleware matters (which it probably does).

mcavage: Pretty sure this is actually node that's biting you (as in your data is emitted to nowhere). Try this:

  var server.createServer();
  server.pre(restify.pre.pause());
  ...
Matt Richards
  • 1,477
  • 2
  • 14
  • 21