Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

New error handling method loses error descriptions #723

Closed
raydog opened this Issue · 27 comments

4 participants

Raymond Myers TJ Holowaychuk Douglas Christopher Wilson Roman Shtylman
Raymond Myers

For example, in middleware/json.js, line 71:

next(400, "invalid json, empty body')

This passes the error along to bodyParser.js, line 54, which does:

if (err) return next(err);

The problem is that we lose the detailed error message, and the error that we see is merely the HTTP status description doubled. (IE: Bad Request: Bad Request) This makes debugging a bit more difficult.

Each of those next(err) calls should also pass along the detailed message, or we could switch back to the utils.error() approach that connect used before. IMHO, having the error isolated to a single parameter makes more sense than having the errors leak out into the second parameter, which typically has non-error data.

TJ Holowaychuk
Owner
tj commented

next(err, msg) should be effectively the same as the old util, if not we have a bug

Douglas Christopher Wilson
Owner

It looks like it is a bug in bodyParser since it tried to compose middleware itself, which bypasses the special next(err, msg) handling.

Douglas Christopher Wilson
Owner

@visionmedia This may be the reason you didn't like that signature in the first place :wink: since middleware can't really be handled just like a plain function anymore, as the callers need to know how to handle the new signature.

TJ Holowaychuk
Owner
tj commented

ah yes, that's super lame haha, reverting! this time I'll make sure to reference the issue hahaha

TJ Holowaychuk tj referenced this issue from a commit
TJ Holowaychuk tj Revert "add support for `next(status[, msg])`"
see #723

This reverts commit 87ffafd.
6db901f
TJ Holowaychuk tj closed this
Roman Shtylman

I think the next(status, msg) case can work. Maybe body parser just needs to be fixed. I will take a look when I am in front of a computer. The idea is that the error object should be created for you and nothing lost. @visionmedia if I fix this issue will you reconsider?

Douglas Christopher Wilson
Owner

@shtylman you also need to fix every use of the limit middleware though out all the other middleware, as it's use suffers from the same problem (the caller does if (err) return next(err) dropping the possible message string). Another issue with your other patch was the removal of utils.error which also broke all third-party code that was using that utility function to make the errors.

TJ Holowaychuk
Owner
tj commented

it's not just bodyParser, we do this sort of composition lots in our apps with custom middleware as well

TJ Holowaychuk
Owner
tj commented

although the utils are private so they shouldn't have been used anyway

Roman Shtylman
Douglas Christopher Wilson
Owner

@visionmedia Ah, I didn't know that utils were private, especially since I didn't notice anywhere saying they were and they are exposed at require('connect').utils.

TJ Holowaychuk
Owner
tj commented

they were exposed originally for Express but that was kinda weird to begin with since they should have been in npm as much as possible

Douglas Christopher Wilson
Owner

Perhaps this calls for an HTTP error factory module, then? :smile:

Roman Shtylman
Roman Shtylman

Wait, unless I am missing something. Nothing was broken. There are tests to check for a proper body. @raydog can you present some code that is failing and describe how you expect it to work?

Roman Shtylman

to me the existence of util.error clearly shows what we really want to be happening. That is why I proposed next(status, msg) as a special case. We should not go cray with next, but given that it is a good way to indicate a specific error code (which is a very common usecase for a web app) I see no reason why this should not exist.

Douglas Christopher Wilson
Owner

You can see the behavior reversion if you add this to test/bodyParser.js (which is probably should be):

  describe('with application/json', function(){
    it('should next(err) on empty JSON', function(done){
      var app = connect();

      app.use(connect.bodyParser());

      app.use(function(req, res){
        res.end('whoop');
      });

      app.use(function(err, req, res, next){
        err.message.should.equal('invalid json, empty body');
        res.statusCode = 500;
        res.end();
      });

      app.request()
      .post('/')
      .set('Content-Type', 'application/json')
      .write('')
      .end(function(res){
        res.statusCode.should.equal(500);
        done();
      });
    });

    it('should next(err) on invalid strict JSON', function(done){
      var app = connect();

      app.use(connect.bodyParser({'strict': true}));

      app.use(function(req, res){
        res.end('whoop');
      });

      app.use(function(err, req, res, next){
        err.message.should.equal('invalid json');
        res.statusCode = 500;
        res.end();
      });

      app.request()
      .post('/')
      .set('Content-Type', 'application/json')
      .write('"string"')
      .end(function(res){
        res.statusCode.should.equal(500);
        done();
      });
    });
  });
Roman Shtylman
Douglas Christopher Wilson
Owner

I'm not sure what is wrong with that command and the tests (I haven't written tests for connect before). You need to run it with mocha manually, like ./node_modules/.bin/mocha test/bodyParser.js; the assertions on the message seem to be eaten.

Roman Shtylman

Hm, it does seem that make (which runs tests and running it manually produce different behavior. This is a bit unsettling. @visionmedia thoughts?

Douglas Christopher Wilson
Owner

@shtylman it's because the way the other tests a copied are testing the status message in such a way that doesn't work. I'm going to change the tests I made you they actually fail in a moment.

TJ Holowaychuk
Owner
tj commented

i dont use npm test ever, npm scripts make zero sense to me, npm isn't a makefile

Roman Shtylman
Douglas Christopher Wilson
Owner

Here are the adjusted tests that will fail properly:

  describe('with application/json', function(){
    it('should next(err) on empty JSON', function(done){
      var app = connect();

      app.use(connect.bodyParser());

      app.use(function(req, res){
        res.end('whoop');
      });

      app.use(function(err, req, res, next){
        err.message.should.equal('invalid json, empty body');
        res.statusCode = 500;
        res.end();
      });

      app.request()
      .post('/')
      .set('Content-Type', 'application/json')
      .write('')
      .end(function(res){
        res.statusCode.should.equal(500);
        res.body.should.be.empty;
        done();
      });
    });

    it('should next(err) on invalid strict JSON', function(done){
      var app = connect();

      app.use(connect.bodyParser({'strict': true}));

      app.use(function(req, res){
        res.end('whoop');
      });

      app.use(function(err, req, res, next){
        err.message.should.equal('invalid json');
        res.statusCode = 500;
        res.end();
      });

      app.request()
      .post('/')
      .set('Content-Type', 'application/json')
      .write('"string"')
      .end(function(res){
        res.statusCode.should.equal(500);
        res.body.should.be.empty;
        done();
      });
    });
  });
Roman Shtylman
Douglas Christopher Wilson
Owner

@shtylman that is right. It's exactly what the initial issue text said.

Roman Shtylman
Roman Shtylman

@dougwilson I read that as needing to pass msg along explicitly while it should happen through arguments. My reading comprehension is not what it used to be :)

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.