I'm new to using node.js and right now I'm working on an API which queries mongodb.
The following function apiRequest needs to call two functions, each of which performs a seperate db query.The problem with the current function is that if one of the query has some sort of error, I wouldnt be able to catch it.
What is the best way to implement this so its properly error handled. Someone pointed me to the async library and mentioned that I had to do something with promises but I really cant figure it out. Ideally I wouldnt want to change the definition of dbQueryOne and dbQueryTwo since they are being used in other places aswell.
exports.apiRequest =function(req,res) {
dbQueryOne(req.body.inputA);
dbQueryTwo(req.body.inputA);
res.send('Moved For Further Action',200);
}
exports.apiRequest = function(req,res) {
dbFuncs = [dbQueryOne(req.body.inputA), dbQueryTwo(req.body.inputA)];
Promise.all(dbFuncs)
.then(result => {
res.send('Moved For Further Action',200);
})
.catch(err =>{
//catch err
});
}
You can use promise.all to run multiple queries and catch any error that has occurred in the catch block
Related
We use AWS Lambda for the backend of our mobile application. I just realized that our uncaught exceptions were not being logged correctly so we could be alerted to them. I realize that we could use something like this
process.on('uncaughtException', (err) => {
console.log(...)
process.exit(1) //mandatory (as per the Node docs)
})
This has a lot of problems though as I do not believe we could push the error into our SNS log stream. Ideally, we'd like to put a try catch block around some of our main processing code, but this does not work as its getting called asynchronously and it does not get caught
async.waterfall([
async.apply(verifyCacheIsReady, request_data),
async.apply(verifyRequestAndGetUser, request_data),
async.apply(logSession, request_data)],
function (command_callback)
{
},
function(err)
{
}
I realize I could try catch in all of this functions, but this is a simplified version. Is there a good way to catch something that happens in this block of code?
This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 4 years ago.
I'm trying to send back results data from my API call in Node. I have an HTML form with a search bar set up that takes the search term and fires off a search with that term.
Right now the data gets sent back and is empty on the first click, but when I click again, the data from the previous call is sent back to my HTML page, so I know there's something going on in regards to callbacks. I could use a setTimeout on the res.json() but that seems a little...juvenile.
I am pretty new to Node and I know the solution is rather simple...but I can't quite seem to figure it out.
Promises, callbacks, async. Maybe I'm just a little confused on where they go...
var result;
var Questrade = require("questrade");
var qt = new Questrade("env.KEY")
qt.account = "env.ACCOUNT";
qt.on("ready", function(err) {
if (err) {
console.log(err);
}
});
function searchQt() {
qt.search(searchTerm, function(err, symbols) {
if (err) {
console.log(err);
}
result = symbols;
});
}
app.get("/search", function(req, res) {
searchTerm = req.query.symbol;
searchQt();
res.json(result);
});
I'm expecting to receive my data back on time.
Easiest and most incremental solution would be to move res.json(result) to the callback where the value of result is received.
function searchQt(res) { // <-- note added argument
qt.search(searchTerm, function(err, symbols) {
if (err) {
console.log(err);
}
result = symbols;
res.json(result); // here it is!
});
}
app.get("/search", function(req, res) {
searchTerm = req.query.symbol;
searchQt(res); <-- note added argument
// res.json(result); <-- commented out and moved above
});
You could also make things work with promises or async/await, but since you're already using callbacks, this is the most incremental way to get to working code.
While you're in there, you should remove result from the outer scope. You don't need or want that value preserved between requests. So just res.json(symbols); and get rid of the results variable entirely.
And passing res as an argument like that above is a bit of a code smell. Let's move the call to qt.search() directly into the callback for app.get() to clean things up a tiny bit. This eliminates the searchQt() function entirely:
app.get("/search", function(req, res) {
searchTerm = req.query.symbol;
qt.search(searchTerm, function(err, symbols) {
if (err) {
// handle error here somehow. maybe something like this?
console.log(`An error occurred: ${err}`);
res.status(500).end('An error occurred');
return;
}
res.json(symbols);
});
});
There are still some other improvements possible here. (I'm not sure if the ready event needs to fire before a search is tried, for example. So there might be a race condition there.) Promises or async/await might make this more readable. (People seem to like those better than deeply-nested callbacks. I personally don't mind the nesting, but I get it.) But that hopefully gets you going in the right direction. (And hopefully I didn't add any bugs that weren't there before!)
Background
I have a REST API using MongoDB, Node.js and Express that makes a request to my NoSQL DB and depending on different results, I want to differentiate which error I send the customer.
Problem
The current version of my code has a generic error handler and always sends the same error message to the client:
api.post("/Surveys/", (req, res) => {
const surveyJSON = req.body;
const sender = replyFactory(res);
Survey.findOne({_id: surveyJSON.id})
.then(doc => {
if(doc !== null)
throw {reason: "ObjectRepeated"};
//do stuff
return new Survey(surveyJSON).save();
})
.then(() => sender.replySuccess("Object saved with success!"))
.catch(error => {
/*
* Here I don't know if:
* 1. The object is repeated
* 2. There was an error while saving (eg. validation failed)
* 3. Server had a hiccup (500)
*/
sender.replyBadRequest(error);
});
});
This is a problem, because the client will always get the same error message, no matter what and I need error differentiation!
Research
I found a possible solution, based on the division of logic and error/response handling:
Handling multiple catches in promise chain
However, I don't understand a few things:
I don't see how, at least in my example, I can separate the logic from the response. The response will depend on the logic after all!
I would like to avoid error sub-classing and hierarchy. First because I don't use bluebird, and I can't subclass the error class the answer suggests, and second because I don't want my code with a billion different error classes with brittle hierarchies that will change in the future.
My idea, that I don't really like either
With this structure, if I want error differentiation, the only thing I can do is to detect an error occurred, build an object with that information and then throw it:
.then(doc => {
if(doc === null)
throw {reason: "ObjectNotFound"};
//do stuff
return doc.save();
})
.catch(error => {
if(error.reason === "ObjectNotFound")
sendJsonResponse(res, 404, err);
else if(error.reason === "Something else ")
sendJsonResponse(/*you get the idea*/);
else //if we don't know the reasons, its because the server likely crashed
sendJsonResponse(res, 500, err);
});
I personally don't find this solution particularly attractive because it means I will have a huge if then else chain of statements in my catch block.
Also, as mentioned in the previous post, generic error handlers are usually frowned upon (and for a good reason imo).
Questions
How can I improve this code?
Objectives
When I started this thread, I had two objectives in mind:
Having error differentiation
Avoid an if then else of doom in a generic catcher
I have now come up with two radically distinct solutions, which I now post here, for future reference.
Solution 1: Generic error handler with Errors Object
This solution is based on the solution from #Marc Rohloff, however, instead of having an array of functions and looping through each one, I have an object with all the errors.
This approach is better because it is faster, and removes the need for the if validation, meaning you actually do less logic:
const errorHandlers = {
ObjectRepeated: function(error){
return { code: 400, error };
},
SomethingElse: function(error){
return { code: 499, error };
}
};
Survey.findOne({
_id: "bananasId"
})
.then(doc => {
//we dont want to add this object if we already have it
if (doc !== null)
throw { reason: "ObjectRepeated", error:"Object could not be inserted because it already exists."};
//saving empty object for demonstration purposes
return new Survey({}).save();
})
.then(() => console.log("Object saved with success!"))
.catch(error => {
respondToError(error);
});
const respondToError = error => {
const errorObj = errorHandlers[error.reason](error);
if (errorObj !== undefined)
console.log(`Failed with ${errorObj.code} and reason ${error.reason}: ${JSON.stringify(errorObj)}`);
else
//send default error Obj, server 500
console.log(`Generic fail message ${JSON.stringify(error)}`);
};
This solution achieves:
Partial error differentiation (I will explain why)
Avoids an if then else of doom.
This solution only has partial error differentiation. The reason for this is because you can only differentiate errors that you specifically build, via the throw {reaon: "reasonHere", error: "errorHere"} mechanism.
In this example, you would be able to know if the document already exists, but if there is an error saving the said document (lets say, a validation one) then it would be treated as "Generic" error and thrown as a 500.
To achieve full error differentiation with this, you would have to use the nested Promise anti pattern like the following:
.then(doc => {
//we dont want to add this object if we already have it
if (doc !== null)
throw { reason: "ObjectRepeated", error:"Object could not be inserted because it already exists." };
//saving empty object for demonstration purposes
return new Survey({}).save()
.then(() => {console.log("great success!");})
.catch(error => {throw {reason: "SomethingElse", error}});
})
It would work... But I see it as a best practice to avoid anti-patterns.
Solution 2: Using ECMA6 Generators via co.
This solution uses Generators via the library co. Meant to replace Promises in near future with a syntax similar to async/await this new feature allows you to write asynchronous code that reads like synchronous (well, almost).
To use it, you first need to install co, or something similar like ogen. I pretty much prefer co, so that is what i will be using here instead.
const requestHandler = function*() {
const survey = yield Survey.findOne({
_id: "bananasId"
});
if (survey !== null) {
console.log("use HTTP PUT instead!");
return;
}
try {
//saving empty object for demonstration purposes
yield(new Survey({}).save());
console.log("Saved Successfully !");
return;
}
catch (error) {
console.log(`Failed to save with error: ${error}`);
return;
}
};
co(requestHandler)
.then(() => {
console.log("finished!");
})
.catch(console.log);
The generator function requestHandler will yield all Promises to the library, which will resolve them and either return or throw accordingly.
Using this strategy, you effectively code like you were coding synchronous code (except for the use of yield).
I personally prefer this strategy because:
Your code is easy to read and it looks synchronous (while still have the advantages of asynchronous code).
You do not have to build and throw error objects every where, you can simply send the message immediately.
And, you can BREAK the code flow via return. This is not possible in a promise chain, as in those you have to force a throw (many times a meaningless one) and catch it to stop executing.
The generator function will only be executed once passed into the library co, which then returns a Promise, stating if the execution was successful or not.
This solution achieves:
error differentiation
avoids if then else hell and generalized catchers (although you will use try/catch in your code, and you still have access to a generalized catcher if you need one).
Using generators is, in my opinion, more flexible and makes for easier to read code. Not all cases are cases for generator usage (like mpj suggests in the video) but in this specific case, I believe it to be the best option.
Conclusion
Solution 1: good classical approach to the problem, but has issues inherent to promise chaining. You can overcome some of them by nesting promises, but that is an anti pattern and defeats their purpose.
Solution 2: more versatile, but requires a library and knowledge on how generators work. Furthermore, different libraries will have different behaviors, so you should be aware of that.
I think a good improvement would be creating an error utility method that takes the error message as a parameter, then does all your ifs to try to parse the error (logic that does have to happen somewhere) and returns a formatted error.
function errorFormatter(errMsg) {
var formattedErr = {
responseCode: 500,
msg: 'Internal Server Error'
};
switch (true) {
case errMsg.includes('ObjectNotFound'):
formattedErr.responseCode = 404;
formattedErr.msg = 'Resource not found';
break;
}
return formattedErr;
}
I have a route that first need to query the database, then with the results, query another web service, then with that result render the page.
I have that flow worked out and am trying to figure out the error handling. Given that i talk to multiple service, I'm trying to massage the error before returning them to express.
Here is the structure of the code for the route:
Models.Episode.findById(request.params.episodeID)
.catch(function (error) {
throw (throwjs.notFound());
})
.then(function (episode) {
if (episode.getUser().id !== request.user.href) {
return next(throwjs.unauthorized("You do not have access to this podcast"));
}
return doSomeOtherAsyncStuff();
})
.then(function (queryResponse) {
renderPage();
})
.catch(function (error) {
next(error);
});
My problem is with the first catch. My goal in this catch is to repackage the error and stop the execution and send the error to express middleware.
With the way it is written above, the execution stops, but my express error handler are not called.
I tried rewriting the first catch as
.catch(function(error){
return next(error);
})
But that does not solve the issue. The only solution i found is to move the catch to the end. But then i lose context of the failure location.
Any clue as to what i'm doing wrong?
Thanks, olivier
I'd recommend taking a different approach so you don't have to rely on long running promise chains. With the following approach, you've decoupled your authorization and and validation to separate middleware, since they're not necessarily a concern of the actual episode handler itself. Plus this approach is more idiomatic to express.
An added bonus is that you're free to pass errors down to an error handler so you further decouple your errors from your route handlers.
function validateEpisode(req, res, next) {
Models.Episode
.findById(req.params.episodeID)
.then(function(episode) {
req.yourApp.episode = episode;
next() // everything's good
})
.catch(function(error) {
// would be better to pass error in next
// so you can have a general error handler
// do something with the actual error
next(throwjs.notFound());
});
}
function authUserByEpisode(req, res, next) {
if (req.yourApp.episode.getUser().id !== req.user.href) {
next(throwjs.unauthorized("You do not have access to this podcast"));
}
next(); // authorized
}
function episodeController(req, res) {
// do something with req.yourApp.episode
}
app.get('/episode/:id', validateEpisode, authUserByEpisode, episodeController)
Well after all, this is related to the throwjs framework I'm using and the fact that I'm using incorrectly
throw (throwjs.notFound());
should be
throw (new throwjs.notFound());
...
Try catch is used to catch errors and report to user. all said and fine. But where exactly one has to put the try-catch. Or What exactly has to go inside try catch on a usual basis.
Most importantly, is it absolutely a good coding practice to have a try catch block?
I think it is good practce to use a try catch if it will handle errors and prevent the program from crashing.
Taken from W3 Schools:
The try statement lets you test a block of code for errors.
The catch statement lets you handle the error.
The throw statement lets you create custom errors.
The finally statement lets you execute
code, after try and catch, regardless of the result.
An example:
fuction foo()
{
try
{
// Block of code to try
}
catch(e)
{
// Block of code to handle errors
document.getElementById("demo").innerHTML = e.message;
}
finally
{
// Block of code to be executed regardless of the try / catch result
}
}
Here is soem more documentation at W3 Schools: http://www.w3schools.com/js/js_errors.asp
Yes, it absolutely good practice to use try-catch blocks. Here's a rather simplistic (but contrived) demonstration.
function safeParseJSON(json) {
try {
return JSON.parse(json);
} catch(exception) {
// could not parse this JSON
console.error(exception);
} finally {
return null;
}
}
Parsing JSON is the most common scenario I have encountered for using the try-catch construct, hence the example.
However, the usual try-catch mechanism doesn't work when the function is asynchronous. It's essential to understand this if you are ever using a server side Javascript platform.
The standard pattern for async event handling is as follows.
db.connect(options, function connected(err, client) {
if(err) throw err;
client.query(...);
});
Because that callback function is run somewhere else (presumably when the database connects) we can't wrap it with a try-catch block. Instead, most async method calls will pass the error as the first argument to the callback.
This way we can handle the error as and when it happens. If there is no error, null will be passed as the first argument, so that it can be ignored.
A number of implementations of promises try to recreate this mechanism, but in an asynchronous way.
Here's an example with Q:
db.connect(options)
.then(function(client) {
client.query(...);
})
.catch(function (error) {
throw error;
})
.fin(function() {
// finally
db.close();
});
You can also use Q on the client side, if you are working with asynchronous functions.