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

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

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.

Related

express middleware not sending response

I have a delete route that has 2 middleware functions Authcontroller.protect and authcontroller.restrictTo("admin, "lead-guide")
router
.delete(
authController.protect,
authController.restrictTo("admin", "lead-guide"),
tourController.deleteTour
);
Within restrictTo I have a check to see if the user has the proper "role" to perform that task and if they don't, express is supposed ot send a 403. I'm seeing that express never actually sends the response. it enters the if statement(i see the console successfully printing fialure) and then it just skips sending the response.
exports.restrictTo = (...roles) => {
return (req, res, next) => {
console.log(req.user.role);
if (!roles.includes(req.user.role)) {
console.log("failure");
return res.status(403).json({
status: fail,
message: "you do not have permission to perform this action"
});
console.log(req, res);
}
next();
};
};
Put a try/catch in your inner function and see if there's an exception being thrown.
From looking at your code, if the fail variable (which you don't show a definition for) is not defined, then that would throw an exception and keep the res.json() from executing.

My Parse job seems to work repeat itseself over and over again

Write the server part of the app in Parse server, and the job keeps executing over and over again.
Here is the code:
var cloudRequest = {
"U": "jjj",
"T": "ssss",
"D": "tttt"
};
Parse.Cloud.run('joinUTT', cloudRequest, {
success: function(result) {
console.log("Done with joinUTT");
},
error: function(error) {
console.log("Error after joinUTT");
}
});
Any idea how to make it run just once?
Thanks!
I ran into this problem before - really hard to track down! Here's what has helped me:
In your Cloud Code make sure to explicitly call response.success() and response.error().
If you have no results to return, still define your Cloud Code function with (request, response) and call response.success(""); It is key to include "".
My guess is that in absence of explicit success/error Parse continues to retry until it gets one of these results.

Error Handling ExpressJS and MongoDB

What is the suggested way of error handling in ExpressJS and Mongoose.
app.get('/', function(req, res) {
Subjects.find({}, function(err, subjects) {
if (err) {
return res.json(err);
}
res.render('list', {subjects: subjects});
});
});
I just returned the error in json. Any suggestions? Thanks
It depends on what that error is, but I would usually redirect via res.redirect to an 'Error' url, with details of the error.
You could test for the details of the error, and re-run a query (dependent on what the error is of course) but usually if the callback is throwing an error, it's terminal, so log it, redirect, and inform the user in a nice way.
(Or of course, return JSON and handle your response client side, with no redirect)
EDIT
As per comment from Paul -
I didn't mean to return the exact details to the user about the error.
Simply "Database error" or something like that would be more appropriate, depending on what the error was.

No result when Rally.data.WsapiDataStore lacks permissions

I'm calling Ext.create('Rally.data.WsapiDataStore', params), and looking for results with the load event.
I'm requesting a number of objects across programs that the user may or may not have read permission for.
This works fine for queries where the user has permissions. But in the case where the user does not have permission and presumably gets zero results back, the load event does not seem to fire at all. I would expect it to fire with the unsuccessful flag or else to return with empty results.
Since I don't know that the request has failed, my program waits and waits. How can I tell if a this request fails to return because of security?
BTW, looking at the network stats, I believe all my requests get a "200 OK" status back.
Here is the method I use to create the various data stores:
_createDataStore: function(params) {
this.openRequests++;
var createParams = {
model: params.type,
autoLoad: true,
// So I can later determine which query type it is, and which program
requestType: params.requestType == undefined ? params.type : params.requestType,
program: this.program,
listeners: {
load: this._onDataLoaded,
scope: this
},
filters: params.filters,
pageSize: params.pageSize,
fetch: params.fetch,
context: {
project: this.project,
projectScopeUp: false,
projectScopeDown: true
},
pageSize: 1 // We only need the count
};
console.log('_createDataStore', this.program, createParams.requestType);
Ext.create('Rally.data.WsapiDataStore', createParams);
},
And here is the _onDataLoaded method:
_onDataLoaded: function(store, data, successB) {
console.log('_onDataLoaded', this.program, successB);
...
I only see this function called for those queries for which the account has permissions.
Are you getting any request for Defect.js or HierarchicalRequirement.js? When I simulate the issue you are seeing the request for TypeDefinition.js fails when it is building the model because the user doesn't have access to the specified project. This seems like a little bug to me. You should be able to work around it by explicitly fetching the model for a type for a specified workspace and then using that in your store.
Rally.data.ModelFactory.getModels({
types: ['Defect', 'UserStory'], //more types, etc...
context: Rally.environment.getContext().getDataContext(), //use workspace
success: function(models) {
//your code here
}
});

Why doesn't dojo.io.script.get() execute the provided error function when receiving a 404?

I am trying to use the following to do a cross-domain get:
dojo.io.script.get({
url: myUrl,
callbackParamName: "callback",
preventCache: true,
load: dojo.hitch( this, loadFunction ),
error: dojo.hitch( this, function() {
console.log('Error!!!');
})
});
The load function runs fine, however, when the server returns a 404, the error function does not run. Can anyone tell me why?
EDIT
After some investigation, I found that a timeout and handler could be implemented in the following way:
dojo.io.script.get({
url: myUrl,
callbackParamName: "callback",
timeout: 2000
}).then(function(data){
console.log(data);
}, function(error){
alert(error);
});
This uses functionality provided by the dojo.Deferred object.
When accessing server with script tags (that what dojo.io.script.get does), status code and headers are not available.
You may try some other ways to detect a problem, like using a timeout and analyzing a content of a script. The latter is problematic for JSONP calls (like in your example).
I realize this is old but I thought I'd share a solution in case others, like I had, come across this thread.
dojo.io.script is essentially adding a <script/> to your html page. So you can try this:
var script = document.createElement('script');
script.setAttribute('type', 'text/javascript');
script.setAttribute('src', myUrl);
script.onerror = function() {
debugger
}
script.onload = function() {
debugger
}
document.getElementsByTagName('body')[0].appendChild(script);
That way if the script fails to load the onerror event is called.
*This may not work in every instance but is a good start