‫All right!
‫And now to finish this section,
‫let's learn how to catch uncaught exceptions.
‫But what exactly are uncaught exceptions?
‫Well, all errors, or let's also call them bugs,
‫that occur in our synchronous code
‫but are not handled anywhere are called uncaught exceptions.
‫And like before, so just like with the unhandled rejections,
‫we also have a way of handling uncaught exceptions.
‫So let me quickly show you
‫an example of an uncaught exception.
‫So let's simply pretend that we're trying
‫to console.log something that doesn't exist.
‫And so right away, we get this error here, x is not defined,
‫and then by default, we get this entire stack trace here
‫printed to the console.
‫All right.
‫And now, to fix this, this is very similar to doing
‫the unhandled rejections.
‫So again, we're listening to an event,
‫this time it's called uncaughtException.
‫And of course it needs to be in quotes.
‫And then just like before, we pass in our callback function.
‫Okay.
‫And now actually what we're doing here is very similar
‫to what we did here.
‫So we wanna lock the error to the console
‫so that it then shows up in the logs in our server, okay?
‫So, giving us a way of then fixing the problem.
‫And then we want to gracefully shut down the server.
‫So let's, well actually here I want
‫to print the entire error to the console,
‫and not just the message, okay?
‫And let's also change the order here,
‫but that's it.
‫So the rest is the same.
‫And here it's of course
‫UNCAUGHT EXCEPTION!
‫Now I could refactor this here into a nice function,
‫but let's just keep it like this, all right?
‫Okay, so let's now rerun this.
‫And so let's take a look at what we have here.
‫And indeed, we now see UNCAUGHT EXCEPTION!
‫Shutting down.
‫All right?
‫And actually this again prints the entire stack
‫to the console, but I don't really want that.
‫I don't like that.
‫So let's just actually go back to what we had here.
‫So err.name and then err.message.
‫Okay, and so now we have the ReferenceError
‫that x is not defined, okay?
‫And let's just put the same here.
‫So just like it was before.
‫All right.
‫And that's actually all there is
‫to catching uncaught exceptions.
‫Now while here in the unhandled rejection,
‫crashing the application like we did here is optional,
‫when there is an uncaught exception,
‫we really, really need to crash our application
‫because after there was an uncaught exception,
‫the entire node process is
‫in a so-called unclean state, all right?
‫And so to fix that, the process need to terminate
‫and then to be restarted, all right?
‫And again, in production,
‫we should then have a tool in place
‫which will restart the application after crashing.
‫And many hosting services already do that
‫out of the box, all right?
‫So, completely automatically without
‫us having to do anything.
‫Now, in Node.js, it's not really a good practice
‫to just blindly rely on these two error handlers
‫that we just implemented here, okay?
‫So ideally errors should really be handled
‫right where they occur.
‫So for example, in the problem connecting to the database,
‫we should of course add a catch handler there
‫and not just simply rely on the
‫unhandled rejection callback that we have here, okay?
‫And some people even say that we shouldn't use these at all,
‫but I disagree with that.
‫I think that as a safety net, let's say,
‫they can be very useful and play a part in our application.
‫Now actually this handler here
‫should be at the very top of our code, okay?
‫Or at least before any other code is really executed.
‫Because watch what happens if I move this line of code here
‫before this handler.
‫So if I put it here, for example,
‫and then give it a save,
‫then you actually see that our handler
‫does not catch this exception, so this error here, right?
‫And so that's because only here at the end
‫we actually start listening for an uncaught exception.
‫But in this case here, the uncaught exception
‫happens before we even listen to that event.
‫And so therefore, we have no way of catching it, right?
‫And so we should ideally put it here, right at the top,
‫again before any other code executes.
‫Especially the one in our application.
‫So let's put it actually right here.
‫Now the problem here will be
‫that the server is not defined at this point.
‫But that's not a problem,
‫because actually we don't need the server here
‫at all, all right?
‫And that's because these errors,
‫so these uncaught exceptions,
‫they are not gonna happen asynchronously.
‫So they are not gonna have anything to do
‫with the server actually.
‫So we don't need this here at all.
‫We can just save it here,
‫and so now we have it before we actually require
‫our main application.
‫And so if we now have an error,
‫let's try it first here,
‫so you see that now we're back
‫to actually catching it in our error handler.
‫But if we now had this code, for example inside of app.js,
‫let's say, it doesn't really matter,
‫let's just say it's here,
‫and if we now run this, well then you see
‫that we're still catching that exception
‫in our error handler, which before would not be the case.
‫All right?
‫And now just for an experiment,
‫what do you think if we put this code
‫right here in this middleware function?
‫What do you think is gonna happen
‫when we save this file now?
‫So x is still not defined anywhere,
‫but let's take a look at what happens
‫when we now run this code.
‫And so now we actually have no error.
‫Or actually we do, but that's only
‫because of our unhandled rejection,
‫which is due to the fact
‫that our password here is still wrong.
‫So if we save that and now save it again,
‫you should see no error at all.
‫And indeed, we don't.
‫And why is that?
‫Well, it's because this middleware function here of course
‫is only called as soon
‫as there actually is a request, right?
‫And so let's see what happens when we do a request.
‫And so let's do a Get All Tours request.
‫And let's wait for it.
‫And, here we get a "Something went very wrong!"
‫error message with the 500,
‫and that's also because we are still
‫in production mode, okay?
‫But anyway, getting this message here, remember,
‫means that we have a nonoperational error here.
‫So basically an error that we did not create ourselves.
‫And so, right this, we now enter here
‫in our errorController, we go right here, right?
‫So into this else branch here in the sendErrorProd function.
‫And actually you see the error
‫down here in the console as well, okay?
‫And so that's what happens when there is an error
‫inside of any Express middleware, right?
‫So Express, when there is an error,
‫will automatically go to the error-handling middleware
‫with that error, okay?
‫And so that's why when we get an error
‫here in any of our middleware function,
‫it will immediately go here into this handler, okay?
‫And since we're in production,
‫it will enter this block here,
‫but since it's not a CastError,
‫and not this error, and not a ValidationError,
‫then as soon as the error is actually sent,
‫right here, we then enter this block.
‫And again, that's why we send this generic error, all right?
‫Let's now actually exit this mode here
‫and go back to our normal npm start.
‫And so right now, our error will be sent like this, right?
‫So send development error will give us all the details
‫about the error that is happening.
‫And so now indeed we get ReferenceError: x is not defined.
‫Okay?
‫So in app.js, line 21.
‫And so, line 21 is where it is,
‫but let's get rid of it.
‫I just wanted to show it to you.
‫Okay?
‫Anyway, with this, we actually close
‫our error handling section.
‫And there could be an entire course on error handling
‫with Node and Express, because it really is
‫an insanely complex topic.
‫But, in this section, you learn the essentials
‫that you need to know in order to really get started
‫building amazing applications.