Execute code on error - node.js

I want to execute a code of automated mail whenever there is any kind of error from any of the API.
Though this is possible to write that code in catch block of a remote method but my code base is too long and hence this is not a best fit.
Another issue with this is approach is for API which are not custom remote method and are generated by loopback, it is hard to use catch block with them.
Can someone help me with an easy approach where I need to write code once and the end result will be whenever there is an error in any of my API my code for mail runs automatically.

Got the answer after struggling for a day.
Loopback provides RemoteHook (afterRemoteError) for a model-method,
_modelName_.afterRemoteError( _methodName_, function( ctx, next) {
//...
next();
});
So whenever a particular method returns any error this block of code is executed.
Read more about remote hooks : https://loopback.io/doc/en/lb2/Remote-hooks.html
To make this block of code run every time any method returns error, we can use wildcards
_modelName_.afterRemoteError(** , function( ctx, next) {
//...
next();
});
Read more about wildcards here : https://loopback.io/doc/en/lb2/Remote-hooks.html#wildcards

You should take a look at Loopback https://github.com/strongloop/strong-error-handler
I also strongly suggest integrating a service like Rollbar.

Related

Express.js : about the behavior of next()

I'm learning to create web applications using Express.js.
In the process, we tried to implement a feature to prevent users from accessing certain pages when they are not logged in.
// teamController.redirectView : Redirect the screen according to res.locals.redirect
app.get('/user/:id/team/member', teamController.showMember, teamController.redirectView)
// The following is a middleware function written in another file(teamController.js)
showMember: (req, res, next) => {
// I want to set the redirect to the '/login' and skip the following process when no user are logging in.
if(!res.locals.loggedIn) {
res.locals.redirect = 'login'
next()
}
// access the property that is set only when the user logs in
let userID = res.locals.currentUser.userID
// Other processes...
When I accessed the URI when the user was not logged in, I was indeed taken to the login page, but I got the following error in the console.
TypeError: Cannot read property 'userID' of undefined
at // the position of 'let userID...'
Error occured: TypeError: Cannot read property 'userID' of undefined
// Abbreviated below...
Does this mean that excuting next() does not skip the following process, like 'return' does?
Or is there some fatal error that is causing this error?
Can you please help me?
I could have avoided the error by enclosing all subsequent processes in 'else', but if there is a better way, I would appreciate it if you could tell me that too.
Does this mean that executing next() does not skip the following process, like 'return' does?
Exactly. Calling next() alone doesn't stop further execution.
This is actually intentional because it allows for additional logic without making the client wait longer (especially with multiple middle-wares).
However to solve your problem, you can combine your next() and a return:
if(!res.locals.loggedIn) {
res.locals.redirect = 'login';
return next();
}
This way you don't have to warp all the code below in an else.
It's a common practice as well, as described here.
You must use return next() or the code keeps executing after you call next()

Loopback beforeRemote for PUT requests

Using Loopback framework, I want to perform some operations before the Item is edited hence I am trying this but unable to bind this to the update hook.
Item.beforeRemote("update", function(ctx,myitem,next) {
console.log("inside update");
});
Instead of update I have tried with updateAttributes,updateById, create but none works. This kind of beforeRemote hook works well with create on POST, but unable to get it with PUT during edit.
The last solution left with me is again inspect the methodString with wildcard hook but I want to know if there is anything documented which I could not find.
Item.beforeRemote("**",function(ctx,instance,next){
console.log("inside update");
});
I know that two year have passed since this post was opened, but if any body have the same question and if you use the endpoint your_model/{id} the afterRemote hook is replaceById.
If you need to know which method is fired in remote hook use this code:
yourModel.beforeRemote('**', function(ctx, unused, next) {
console.info('Method name: ', ctx.method.name);
next();
});
Contrary to the comments, save is a remote hook, not an operation hook, but you want to use it as: prototype.save. The relevant operational hook would be before save. You can see a table of these on the LoopBack docs page. I would probably implement this as an operational hook though, and use the isNewInstance property on the context to only perform the action on update:
Item.observe('before save', function(ctx, next) {
if (ctx.isNewInstance) {
// do something with ctx.currentInstance
}
next();
});
Sorry for bumping into old question but its for those who are still searching.
'prototype.updateAttributes' can be used as remote hook for update requests.
and #jakerella , there is no remote hook called 'save' , i myself tried it, but didnt work.
Came here looking for another thing, guess it will be helpful to someone.
For before remote model/:id patch method you have to use "prototype.patchAttributes".
On loopback3 for PATCH you can use "prototype.patchAttributes" to sanitize your data before the update.
YourModel.beforeRemote('prototype.patchAttributes', (ctx, unused, next) => {
console.log(ctx.args.data);
next();
});

Handling errors at a global level

I am trying to understand how to build my error handling system for my api.
Let's say I have a the following line in a controller method :
var age = json.info.age;
with
json = {"id":1, "name":"John", info": {"age":27, "sex":"m"}}
Let's say that the object doesn't contain an info field, I'll get the following error TypeError: Cannot read property 'info' of undefined and my server will crash.
Is there a way to make a higher level abstraction and catch all the potential errors that I could have? Or should I have a try/catch system for each of the methods of my controllers?
BEWARE OF THE CODE BELOW, IT WILL BITE YOU WHENEVER IT CAN!
Don't use the code snippet below if you do not understand its
implications, please read the whole answer.
You can use the node way for uncaught errors. Add this in your config/bootstrap.js
Updated the snippet below to add what was said in the comments, also added a warning about using a global to respond to the user.
process.on('uncaughtException', function (err) {
// Handle your errors here
// global.__current__ is added via middleware
// Be aware that this is a bad practice,
// global.__current__ being a global, can change
// without advice, so you might end responding with
// serverError() to a different request than the one
// that originated the error if this one happened async
global.__current__.res.serverError();
})
Now, can doesn't mean should. It really depends on your needs, but do not try to catch BUGS in your code, try to catch at a controller level the issues that might not happen every time but are somehow expected, like a third-party service that responded with empty data, you should handle that in your controller. The uncaughtException is mainly for logging purposes, its better to let your app crash if there is a bug. Or you can do something more complicated (that might be better IMHO), which is to stop receiving requests, respond to the error 500 (or a custom one) to user that requested the faulty endpoint, and try to complete the other requests that do not relate to that controller, then log and shutdown the server. You will need several instances of sails running to avoid zero downtime, but that is material for another question. What you asked is how to get uncaught exceptions at a higher lvl than the controllers.
I suggest you read the node guide for error handling
Also read about domains, even thought they are deprecated you can use them, but you would have to deal with them per controller action, since sails does not provide any help with that.
I hope it helps.
You can check this way if you want to:
if (object != null && object.response != null && object.response.docs != null){
//Do your stuff here with your document
}
I don't really get what is your "object" variable in the first place, so i don't know if you can check it at a different level, is it a sails parameter to your controller ?
So that's how I did it, thanks to Zagen's answer.
module.exports.bootstrap = function(cb) {
process.on('uncaughtException', function (err) {
//Handle your errors here
logger.fatal(err);
global.__current__.res.serverError();
})
cb();
};
I send a generic error 500 to the user if any uncaught exception is thrown, and I log the error to the fatal level. On that way, my server is still accessible 24/7 and I can monitor the logs at another level and trigger an alarm on a fatal error. I can then fix the exception that was thrown.

node.js - perform global procedure before invoke the mapped methods

everyone ! I've this sentence in my app.js:
app.get('/aux/:subject/:data', aux.query);
app.post('/register/:Id', register.create);
app.post('/register/:Id/smsConfirm', register.confirmSms);
app.post('/register/:Id/login', register.login);
app.post('/register/:Id/resetPassword', register.resetPassword);
app.get('/register/:Id/getSms', register.getSms);
And I will have much more because it's the beginning. And i'd like to implement a global function to be executed before any class like aux.query, register.create, etc be invoked.
Basically I'd like to check if the IP is on my black list. If true: Don't execute anything - Throw a 403 instead.
Actually the only way I know to implement this is to put in any method a verification using promises and after check, allow the execution, but I believe that there is a better way to do the things in a global way (maybe not ??)
Can someone give me a good hint ? ty !
You should handle your black list check as middleware if it is a valid test for every endpoint.
function blacklist(req, res, next) {
// check blacklist
// call next() if passed
next();
}
app.use(blacklist);
app.get('/aux/:subject/:data', aux.query);
app.post('/register/:Id', register.create);
app.post('/register/:Id/smsConfirm', register.confirmSms);
app.post('/register/:Id/login', register.login);
app.post('/register/:Id/resetPassword', register.resetPassword);
app.get('/register/:Id/getSms', register.getSms);

node.js middleware and js encapsulation

I'm new to javascript, and jumped right into node.js. I've read a lot of theory, and began well with the practical side (I'm writing an API for a mobile app), but I have one basic problem, which has lead me to middleware. I've successfully implemented a middleware function, but I would like to know if the use I'm giving the idea of middleware is OK, and also resolve the original problem which brought me to middleware. My question is two-fold, it's as follows:
1) From what I could gather, the idea of using middleware is repeating a process before actually processing the request. I've used it for token verification, as follows:
Only one of my urls doesn't receive a token parameter, so
app.js
app.get('/settings', auth.validateToken, auth.settings);
auth.js
function validateToken(req, res, next){ //code };
In validateToken, my code checks the token, then calls next() if everything is OK, or modifies res as json to return a specific error code.
My questions regarding this are: a) Is this a correct use of middleware? b) is there a [correct] way of passing a value onto the next function? Instead of calling next only if everything is OK, is there a [correct] way of calling next either way, and knowing from inside the next function (whichever it is), if the middleware was succesful or not? If there is, would this be a proper use of middleware? This precise point brings me to my original problem, and part two of this question, which is encapsulating functions:
THIS PART WAS FIXED, SEE MY SECOND COMMENT.
2) I discovered middleware trying to simply encapsulate validateToken, and be able to call it from inside the functions that the get handlers point to, for example auth.settings.
I'm used to common, sequential programming, and not in javascript, and haven't for the life of me been able to understand how to do this, taking into account the event-based nature of node.js.
What I want to do right now is write a function which simply verifies the user and password. I have it perfectly written inside a particular handler, but was about to copy-paste it to another one, so I stopped. I want to do things the right way from scratch, and understand node.js. One of the specific problems I've been having, is that the error code I have to return when user and password don't match are different depending on the parent function, so I would need this function to be able to tell the callback function "hey, the password and user don't match", so from the parent function I can respond with the correct message.
I think what I actually want is to write an asynchronous function I can call from inside another one.
I hope I've been clear, I've been trying to solve this on my own, but I can't quite finish wrapping my head around what my actual problem is, I'm guessing it's due to my recent introduction to node.js and JS.
Thanks in advance! Jennifer.
1) There is res.locals object (http://expressjs.com/api.html#res.locals) designed to store data local to the request and to pass them from one middleware to another. After request is processed this object is disposed of. If you want to store data within the session you can use req.session.
2) If I understand your question, you want a function asynchronously passing the response to the caller. You can do it in the same way most node's functions are designed.
You define a function in this way:
function doSomething(parameters, callback) {
// ... do something
// if (errorConddition()) err = errorCode();
if (callback) callback(err, result)
}
And the caller instead of using the return value of the function passes callback to this function:
function caller(req, res, next) {
//...
doSomething(params, function(err, result) {
if (! err && result) {
// do something with the result
next();
} else {
// do something else
next();
// or even res.redirect('/error');
}
});
}
If you find yourself writing similar callback functions you should define them as function and just pass the function as parameter:
//...
doSomething(param, processIt);
function processIt(err, result) {
// ...
}
What keeps you confused, probably, is that you don't treat functions as values yet, which is a very specific to JavaScript (not counting for languages that are little used).
In validateToken, my code checks the token, then calls next() if everything is OK, or modifies res as json to return a specific error code.
a) Is this a correct use of middleware?
b) is there a [correct] way of passing a value onto the next function?
Yes that is the correct way of using middleware, although depending on the response message type and specifications you could use the built in error handling of connect. That is in this example generate a 401 status code by calling next({status:401,stack:'Unauthorized'});
The middleware system is designed to handle the request by going through a series of functions until one function replies to the request. This is why the next function only takes one argument which is error
-> if an error object is passed to the next function then it will be used to create a response and no further middleware will be processed. The manner in which error response is created is as follows
// default to 500
if (res.statusCode < 400) res.statusCode = 500;
debug('default %s', res.statusCode);
// respect err.status
if (err.status) res.statusCode = err.status;
// production gets a basic error message
var msg = 'production' == env
? http.STATUS_CODES[res.statusCode]
: err.stack || err.toString();
-> to pass values down the middleware stack modifying the request object is the best method. This ensures that all processing is bound to that specific request and since the request object goes through every middleware function it is a good way to pass information down the stack.

Resources