Search code examples
error-handlingpromisemodel-validationbookshelf.js

Checkit with bookshelf, how to catch error and stop DB execution?


I'm trying to use checkit with bookshelf and after adding the checkit rules, intentionally violating them, my promise#catch block doesn't seem to be properly catching the errors. (I could also be totally misunderstanding the use of catch here)

var validationRules = new Checkit({
    email: 'required',
    password: 'required'
});

var User = bookshelf.Model.extend({
    tableName: 'users',

    initialize: function() {
        this.on('saving', this.validateSave);
    },
    validateSave: function() {
        validationRules.run(this.attributes);
    }
});

User.forge({}).save().then(function(validated) {
    console.log('this shouldnt trigger');
}).catch(function(err) { // this doesnt seem to be working the way I expect
    console.log(e.message);
});

When I create the empty user object, I'm getting the following unhandled error stacktrace, and also seeing a DB query being built (which may be a separate question for the bookshelf project and what happens when you hook into the 'saving' event)

Possibly unhandled Checkit Errors - email: The email is required; password: The password is     required
    at checkit/checkit.js:105:23
    at tryCatch1 (bluebird/js/main/util.js:45:21)
    at Promise._callHandler (bluebird/js/main/promise.js:597:13)
    at Promise._settlePromiseFromHandler (bluebird/js/main/promise.js:607:18)
    at Promise._settlePromiseAt (checkit/node_modules/bluebird/js/main/promise.js:769:18)
    at Promise._settlePromises (checkit/node_modules/bluebird/js/main/promise.js:884:14)
    at Async._drainQueue (checkit/node_modules/bluebird/js/main/async.js:98:12)
    at Async._drainQueues (checkit/node_modules/bluebird/js/main/async.js:103:10)
    at Async.drainQueues (checkit/node_modules/bluebird/js/main/async.js:37:14)
    at process._tickCallback (node.js:415:13)
{ __cid: '__cid1',
  method: 'insert',
  options: undefined,
  bindings: [],
  sql: 'insert into `users` () values ()' }
ER_NO_DEFAULT_FOR_FIELD: Field 'email' doesn't have a default value

I have 2 questions about this:

  1. Since I have debug: true turned on in my knex config, the block between the stacktrace and the ER_NO_DEFAULT_FOR_FIELD seems to be prepared SQL statements. Given that I introduced Checkit to catch validation errors on the Model level, why is SQL still being executed?
  2. Am I using the #catch block in the correct manner? And if so, why do I still get unhandled error stacktraces. (It looks as though the e.message resulting from the #catch function is actually coming from MySQL rather than from Checkit) If not, what is the correct way to handle errors more gracefully here?

My main sources of information so far have been the bookshelf.js docs(http://bookshelfjs.org/), and the Checkit repo (https://github.com/tgriesser/checkit)


Solution

  • Checkit returns promises, promises work with each-other using return values so by not having return after checkit.run you're not letting bookshelf know when the validation is complete.

    Bluebird (the underlying promises) are letting you know you might have a rejection you're not aware of. In order to correct the code you need to change:

    validationRules.run(this.attributes);

    To:

    return validationRules.run(this.attributes);

    In your validateSave function so the promise can chain.