I've written a few MEAN Stack applications and set up API's but I've always had some level on confusion on whats the best way to handle errors inside an API Routes.
Please do correct me if I explained something wrong or my thinking/concept are flawed. I am explaining what I think is right. just trying to be a better programmer.
When I say errors I mean the following scenarios:
A General error, something you did not predict has happened and needs to be handled, maybe the server is down or the server is overloaded, basically anything that we can't predict that might happen. This type of error mostly is handled here "I think" (see comments below in code):
app.get('/user', isLoggedIn, function(req, res){
User.find(_id, function(err, user){
// HERE I am not sure how to handle this, Maybe we can't reach the DB or anything else could have happened. How do you handle this error so no matter what kind of error it is we can handle it gracefully and the app doesnt crash and we don't lose value data and the user is made aware of the issue.
if(err)
I have seen different ways how people have managed the above error here are a few examples:
if(err)
// I think this is wrong! Maybe okay for development but not for deployment
console.log("The Error is " + err);
if(err)
// Again I think not a good way of handling error because doesn't provide the system or the front-end user with any useful data.
throw err;
if(err)
// Not Sure
res.send(err);
if(err)
res.json(err);
So the above was when we can't predict what kind or when error might occurs but there also another type see below
So lets says we passed the above if(err) stage and went to the else, this is where we CAN predict the errors because this is where User interaction comes into play. For example continuing the example above (see comments in code):
app.get('/user',isLoggedIn,function(req, res) {
User.find(_id, function(err, user) {
if (err){
// NOT SURE WHAT TO DO HERE
}
// HERE lets say the user we are trying to get does not exist, now this is something we can predict, how to handle this not only gracefully so we don't crash the app but also provide the front end user with some useful information.
else if(!user){
}
else if(user){//Do what you were meant to do!}
});
})
Now how I usually manage this type of error is by sending back some information to the front-end user like so:
return(res.json({message: "The user you are trying to find does not exist, contact the system admin please."}));
I send back some JSON data and display on the front end inside a div or an alert box etc.
So these are the two "kinds" or a better word "situations" of errors I deal with. Whats the best way of dealing with them so they the app can manage itself without crashing but also making sure the front-end user knows whats going on so they know their next step. And what are the best practices for handling errors in API's.
I prefer use next and custom Error
Next
app.get('/user', isLoggedIn, function(req, res, next){
User.find(_id, function(err, user){
if (err)
return next(err); // Forwarding error to error-middleware
...or...
throw new Error('Cause'); // If error is critical for app and app must be stopped
...
});
In Error-middleware we can choose how much info send to console/user and how present info
// Detect current environment
if (req.app.get('env') != 'development') {
...
}
// Detect request type
if (req.xhr)
req.json(...)
else
res.render('error.html', ...);
Custom Error
In example above you can throw AuthorizeError and forwarding it by next. More about custom error read here. Imho it's excessively for small application.
Related
So I'm building a React application for a client and they want me to find when a user is not authenticated, and redirect to a different site. When the user is not authenticated, the app returns the errors you see below. Apologies for the blackout, but basically the errors come from the embed itself and not my app so putting try...catch around the authentication/embedding does not work.
The code that kicks off the auth and embed process looks like this. I've simplified it to what's important and removed information about the client.
async function setupEverything(x) {
LookerEmbedSDK.init('<URL>')
await LookerEmbedSDK.createDashboardWithId(x)
.appendTo('#dashboard')
.build()
.connect()
.then(setupDashboard) // Ignore this, has nothing to do with embed.
.catch((error) => {
console.error('An unexpected error occurred', error)
})
}
Essentially the embed is in an iframe, probably the error is thrown from the iframe. Is there a way to listen to this error event given that I cannot access the code within the iFrame? Should I tell my clients it's a lost cause?
Suppose, I have this function with a wrong 'uri' string provided to fetch:
function imgChanger(uri) {
fetch('uri', { mode: 'cors' })//WRONG 'uri' to demonstrate that catch doesn't prevent console's red error
.then(function (response) {
if (!response.ok) {
throw new Error(response.statusText);
}
return response.json();
}).then(function (response) {
img.src = response.data.images.original.url;
}).catch((err)=>{
console.log(err);
});
}
Despite handling the error, I can see a 404 message in the console:
I have two questions regarding this: why is it being shown despite catching it and how do I handle it?
I'm afraid there's little you can do here. There's an Issue 124534: Provide a way not to display 404 XHR errors in console open in Chromium almost 10 (!) years ago:
Chromium always displays HTTP 404s as errors in the Javascript
console. Apart from forcing line noise onto developers when they may
not want it (404s can be spotted easily in the 'Network' tab), I think
this actually goes against the spirit of HTTP. If you have a
telephone direcotry lookup, for example, and you GET
http://myHost/directory/numbers/12345678
... the server should respond with a 404 if that number was not in the
directory. This is even really an 'error' in my opinion - it's just
information. Why should Chromium display this as an error in the
console?
And as you can see, it's still open (and is essentially treated as 'by design'). Here's another telling quote:
8 years gone by and I still cannot control how a client responds to a
request. Our in-house API's have been changed to always respond with
200, with a custom status field to correctly filter what is an actual
error and what is just simply not there.
It's painfully moronic that we have to move away from REST to actually
use a semantic status.
But rejoice! there seems to be a discussion open in 2021, so hopefully we'll get things moving in the end. Now, unfortunately, it's not that easy:
There seems to be general agreement that it would be preferable to
remove these error messages from the console. But it is also very
likely that currently a lot of DevTools users depend on these error
messages in their workflow. We have not yet found a way to reconcile
these 2 sides.
And now the obligatory xkcd comic:
I tried many experiments but I could not get HTTP OutgoingMessage to fire error event ever. But I know OutgoingMessage is basically a WritableStream and as such prone to error.
Also, when I read this official Node.js docs about Anatomy of an HTTP transaction, it is recommended to handle errors on the Response Stream.
If yes, what scenarios will cause error event to fire up? Should I just swallow these errors silently?
I've been wondering the exact same thing this week, and I can't really seem to find any straightforward answers.
I scoured through Koa to see what they do, and it doesn't look like they ever attach an error handler to the res stream at all.
Whatever might cause that stream error must be rare, or doesn't crash your program like the Node tutorial suggests. If it did, Koa would be unusable, which does not seem to be the case since a lot of people use it.
I looked through other HTTP frameworks like Hapi and Express, but their codebases are so complicated I found it hard to draw a similar conclusion. :\
I also found this set of experiments from a few years ago that seem to indicate that Node's tutorial isn't quite lining up with Node's actual behavior:
While this experimentation may not be an exhaustive look at all the things that can go wrong in network programming, the results here seem to indicate that an HTTP response stream will never emit an error event; or, at the very least, that such an error event will never crash the server. So, while you have to bind an "error" event handler to just about every other streams in Node.js, it would seem that you can safely assume the HTTP response stream will never error, no matter what happens. And, that even if the response stream closes, you can continue to write to it / pipe to it without consequence.
For my own project I'm just going to log the error somewhere, just in case.
Handling error is not required for streams or anything in NodeJS, but is good practice. There is even a concept: error-first callbacks in NodeJS and the first parameter in a callback is actually an error object.
Lets imagine case where you don't handle and error:
fs.readFile('./non_existing_file.json', (err, data) => {
// here we don't handle the error
// and if there is an error
// the second parameter will be undefined
let myDataObj = JSON.parse(data)
...more code...
})
Now we did not handled the the error and when trying to parse undefined we get an error which crashes our application. We need to manually start our application.
By handling the error:
fs.readFile('./some_file.json', (err, data) => {
if(err) throw err
// if there is an error
// the rest of the function won't be executed
let myDataObj = JSON.parse(data)
...more code...
})
Now this will log an error telling us what exactly went wrong and our application won't crash, it will just log the error.
It is not necessary to log the error, we just log it to help us debugging. Of course you can safely swallow it by replacing if(err) throw err with if(err) return
It is up to you to decide how to handle errors or to handle them at all. It is good thing to log them and even better to notify your users that something went wrong.
I have published the current version on github: https://github.com/rcbgit/boiler
The user seems to be "logging in". At least the successful redirect happens with valid username/pw and the failure redirect happens with a bad combo. The problem I'm having is that I don't know how to store the user information after the login or validate a page against it (restrict access). I created a basic 'Auth' service that stores the user information but i'm not sure how to use it properly.
I'm also having trouble figuring out how to handle messages back from the server such as "Username already exists!".
Any advice is appreciated!
A couple of things:
1) I assume the flash messages not showing up so well. I had issues with that too, so I reverted to using the session itself to pass the messages. Here is what I did instead that worked just fine:
I changed the req.flash to this:
req.session.signUpMessages.push('That email is already taken.');
then changed in my template to display this variable if it exists, works like a charm.
2) I think you can and should remove the process.nextTick, it's great when you're doing authentication against external APIs that might take a long time, in this case it's more of an overkill IMO. I would remove it.
3) and last but not least, I think you're missing curley brackets..
if (err)
console.log(err);
return done(err);
^^^^^^^^^^^^^^^^
this get's called each time, that's not what you want...:)
should be turned to this:
if (err) {
console.log(err);
return done(err);
}
Try these changes, see if that solves the problems?
I'm currently developing a little Website with Firebase. I got a couple of HTML files and each file contains a logout button which calls the function
function logout(){
auth.logout();
console.log("logout successfull");
location.href="index.html";
}
After getting redirected I tried to login again but it always failed with the following error message:
Error: FirebaseSimpleLogin: An unknown server error occurred.
It took me some time to realise that the redirection to the index page caused the problem. When I delte the location.href="index.html"; line, everything works fine.
Problem is, I really need something that redirects me to the front page, when the user isn´t loged in. Is this a known problem and/or can someone come up with a solution to this problem?
Thanks in advance :)
PS.: I realised that I could "fix" the problem (after getting redirected to the index page) when I cause an error (f.e. calling a undefined function). Idk if this information helps...
Ok, thanks for your reply Kato!
I changed quite a lot, since I started the "project". Instead of using mutliple HTML files I copied everything into the index.html and work now with mutliple (hidden) DIVs.
But unfortunatly, the problem still exists.
I offer two different Login possibilites. One with Facebook (works 100% of the time for me) and one with the SimpleLogin (works barely).
I´m pretty sure I did the initialization the same way like it´s done in the tutorials on firebase.com.
This is how I connect to the Firebase DB
var ref = new Firebase('https://partyfinder-db.firebaseio.com/');
var auth = new FirebaseSimpleLogin(ref, function(error, user) {
if (error) {
// an error occurred while attempting login
alert(error);
} else if (user) {
// Here I work with user.id etc.
} else {
// user is logged out
}
});
And that is how I try to login the user...
function login() {
//I probably should use jQuery here...
var _email = document.getElementById("emailLogin").value;
var _pw1 = document.getElementById("passwordLogin").value;
var _rememberMe = document.getElementById("rememberMe").checked;
auth.login('password', {
email: _email,
password: _pw1,
rememberMe: _rememberMe
});
showMain(); //Hide and show DIVs and stuff...
}
I call this function on the SignIn Button. The whole Javascript file is linked in the head part of the HTML file.
So, calling this function is normally causing the following error
Error: FirebaseSimpleLogin: An unknown server error occurred.
I already figured out that this message only shows up when the connection to the DB already was successful. For example, when I type in an invalide email adress, the following message appears:
Error: FirebaseSimpleLogin: The specified user does not exist.
There are a few things that can "fix" the problem. For example, when I use the Facebook Login and logout after this was successful, I can sign in using firebase simpleLogin. Sometimes (unfortunatly not always) it helps when I`m causing an error, f.e. calling a non existing function. After the error message is displayed in the console, I can continue logging in (successfully).
But to be honest I`ve absolutly no idea what this tells me about the error and if this is somehow a hint to the solution. I also tried to set some breaking points and debug through the relevant code (using google chrome) but didn´t find anything.
I uploaded the page to a free webspace, where you can test this whole thing by yourself.
But please note, this project is just for testing purpos. I´m not planning to release it somehow, it´s just for me to figure out multiple things and I find it easier to learn something when I can set it in a context. I´m pretty sure it´s quite bad coded and contains many mistakes, etc. But I´m always grateful for feedback beside the actual problem :)
For the login you can use
email: user#email.com
password: user
If you use the FB-Login, your Name and your email adress will be saved to the Database (but I can delete this section of the code if you want/need to use it and feel uncomfortable about it).
http://partyfinder.lima-city.de/
Most of the comments are in german, sorry for that...