node.jsexpressqrestifynode.js-connect

Restify.js (Connect/Express) middleware ignoring call to next() within promise callback


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()?


Solution

  • 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());
      ...