‫Hello there.
‫Let's now render some nice error pages to our users.
‫And so to start, let's actually create an error first.
‫So let's open this tour here.
‫No, I don't want to translate.
‫And now let's simply add something to this log here,
‫and so that will then, of course, not be found.
‫Right, and so this is what an error looks like
‫at this point.
‫So simply, all of this JSON here,
‫just like it would look like in Postman.
‫So we've seen this kind of error here before.
‫And so, let's now fix that.
‫But first we actually need to fix this particular error.
‫So right now we get,
‫cannot read property name of null in getTour.
‫Okay.
‫And so that is here in our views controller, getTour.
‫And so in here, we do not have any error handling
‫in case that there is no tour, right?
‫So we have that in all our other route handlers,
‫but in this, we don't have it yet.
‫So let's add that.
‫So if there is no tour, then return
‫and go to the next middleware with a new app error.
‫And probably that's not here yet.
‫And no indeed, it's not.
‫So const.
‫AppError equals.
‫Alright.
‫Error here of course.
‫And then let's say
‫there is no tour with that name.
‫And then it's a 404 for not found.
‫Okay?
‫So let's try that again.
‫And so now we should get a much nicer error.
‫And indeed, we get one.
‫So 404.
‫And keep in mind that this one is now an operational error.
‫So an error that we know that we created ourself basically.
‫And so just like before, that's going to be important for
‫our error handling strategy.
‫So, let's actually talk about that.
‫And so here we're done.
‫And now in our error controller,
‫we have, remember, two functions which send errors
‫back to the client.
‫So we have this one here for development
‫and this one for production.
‫Then in production, we distinguish between
‫operational errors and other unknown errors.
‫Right?
‫And so that's actually what we just talked about before.
‫So for the errors that we know,
‫we send back the real error message
‫because we can be sure that it's not going to be
‫some weird looking error
‫coming somewhere from express or note
‫or something like that.
‫While, one the other hand, when it is an unknown error,
‫well, then we do not want to leak the error details.
‫And so now in this case, with the rendered website,
‫we will actually use the same strategy.
‫Now, what I'm going to do
‫is to simply add the rendering of an error page
‫to each of these functions.
‫And basically, what I'm gonna do is to test
‫if the URL starts with slash API.
‫And so in that case, we send this kind of error, right.
‫But if the URL does not start with API, well in that case,
‫it means that we want to render an error page
‫as a rendered website, okay?
‫So just like we've been doing in this section.
‫Anyway, let's now implement that.
‫And so, we can use request dot original URL.
‫And probably we have used that before.
‫Alright?
‫So original URL is basically the entire URL
‫but not with the host.
‫So it looks then, exactly like the route.
‫And so again, when we're hitting our URL,
‫well, then that route starts with slash API.
‫And so now we can test for that.
‫So we can use a JavaScript function called startsWith.
‫So a function that's available for strings.
‫And then test if it starts with slash API.
‫Right?
‫And so if it does, then this is what we want to do.
‫So simply send down the error as JSON.
‫But if not, well, then we actually want to render an error.
‫So it's still res.status.
‫And to statusCode as well.
‫But in here it is actually render.
‫Then we get the name of the template,
‫and we're going to create this template in a second,
‫but it's going to be called error.
‫And then the data that we want to send there
‫is for now just the title.
‫And I will add some more stuff then
‫once the template is actually done.
‫So something went wrong
‫is going to be the title of this error page.
‫Alright?
‫Oh, actually we do not have access
‫to the request variable here.
‫And its function.
‫And so let's add that.
‫Request here.
‫And we're also going to be needing it here.
‫This one.
‫And so let's add that here as well.
‫So right here.
‫Okay.
‫So, now we actually need to create this page,
‫or this template, called error.
‫And once more, I already have a simple template for that.
‫So it's in dev-data, templates, and errorTemplate.
‫Okay?
‫So let's copy this.
‫And then create a view for that.
‫error.pug.
‫Okay.
‫And so here we have a simple h2 which says,
‫uh oh, something went wrong.
‫Then (laughs) some fun emojis there.
‫They're not really fun.
‫And then here we want to be able to also pass in a message.
‫Alright?
‫So let's add this equal to msg, just shorthand for message.
‫Alright?
‫And that's actually it.
‫So let's close that and let's pass in that message.
‫So msg is then set.
‫And let's really set it to error dot message.
‫Okay?
‫And we're doing here because we are in development.
‫So keep that in mind.
‫Let's also add some comments here.
‫API.
‫Let's put that here.
‫The rendered website.
‫So we're doing it like this, with error message,
‫again because in development,
‫it doesn't really matter if we leak all of the error details
‫to our page, right?
‫Because no one is really going to see it since, yeah,
‫we're in development.
‫So that should be working now.
‫So all we should need to do now is reload this page.
‫But now something is wrong here.
‫So it says it didn't send any data.
‫So let's go back here.
‫Well as a first problem I'm seeing here,
‫that I should have the status code and not just the status.
‫That's all to check if we got some error here.
‫Oh yeah.
‫Actually there is errors.
‫So, it actually was the invalid status code.
‫So here it should be code.
‫Let's give that another save.
‫Reload it.
‫And now we get some error page here.
‫Well, it's not really formatted.
‫But still, it has the title and more importantly,
‫it has this message that we just passed in.
‫So there is no tour with that name.
‫And so that comes exactly from our views controller.
‫So right from here.
‫So remember that logic where we create an error here
‫which is then passed down to our global error
‫and Lint middleware.
‫Right?
‫And so that's the one that will pick up these errors
‫and send them down to the client.
‫Now in our case, we get this error
‫because here in our template,
‫we still forgot to do something.
‫Which is simply to extend, of course, our main template.
‫Right?
‫So we need to say extend to base template.
‫And then as always, create that block here.
‫So block content.
‫And then all of this needs to be in there.
‫And so basically here we're doing
‫the exact same thing as we did in all the other templates.
‫So basically injecting this content here
‫into the content blog in the base template.
‫So if we reload that now, then it finally looks as intended.
‫Alright?
‫And now, if we actually did have some error in our code,
‫and so let's again say
‫that we do not have this error handling here,
‫then of course the entire error is leaked to the client.
‫So cannot read property name of null.
‫And of course, we do not want our website visitors
‫to get this kind of error, right?
‫No one would really understand what that means.
‫And so in our production error handler,
‫let's now take care of that.
‫So down here in our error controller,
‫now let's apply the same logic that we have here.
‫So testing if we are currently handling the API or not.
‫And of course there could be more elegant ways
‫of doing this.
‫For example, you could have one completely separate
‫error handling middleware just for the API,
‫and one for the rendered website, right?
‫But again, I just want to keep it kind of simple here.
‫Okay?
‫So in this case, that's really my main goal.
‫Alright.
‫Let's select all of this.
‫Oh, what happened there?
‫Ah, here we go.
‫Okay.
‫So that's for the API.
‫And now we will actually have something very similar.
‫So this one is, again, for the rendered website.
‫Let's call it B here and A for this one.
‫So just to separate it a bit better.
‫So we have and then B down here.
‫Anyway, this will look a bit similar to this one.
‫And so if we have an operational error,
‫then basically the error page
‫should look just like we had here before.
‫But in case that it's a programming or unknown error,
‫well then we do not want the complete message,
‫but instead just a very generic message.
‫So something like please try again later.
‫Alright?
‫Now let's see what kind of error we get here.
‫And apparently, we get something called a
‫lonely if statement here.
‫Right.
‫So yes, Lint doesn't really want us
‫to only have an if inside of an else block.
‫And I agree that it's kind of not
‫a beautiful coding practice.
‫And so in fact, let's fix that
‫by getting rid of this else here.
‫Give it a save.
‫And then that error is gone.
‫But now we need to make sure that this here
‫really ends the request response cycle.
‫And so we need to return here and here as well.
‫Alright.
‫Now, another ESLint error, unnecessary else after a return.
‫And indeed, that is true as well.
‫And I have been actually following this rule
‫throughout the course because I like it myself
‫as a coding practice.
‫And so, yeah, let's get rid of this else here then.
‫I really believe, and I have believed it for a long time,
‫that it looks a lot nicer without these if else statements,
‫but instead only with an if, like this here,
‫and then include the else outside of that.
‫Okay, that's what we have here now.
‫Let's also put A and B here.
‫B.
‫And in fact, let's do the exact same thing here.
‫So return.
‫Return this one as well.
‫Then here, A and B as well.
‫So, that in fact looks cleaner to me.
‫Now we have A here and A here again,
‫but, well, never mind at this point.
‫Alright.
‫So return here.
‫Return here.
‫And before it yells at me, let's remove this.
‫And so that is better again.
‫So put this out here.
‫And that should actually be it.
‫Alright?
‫Let's just for the sake of completeness
‫copy this comment here as well.
‫And then call this one B again.
‫Alright.
‫Perfect.
‫Let's actually copy this one here as well
‫to the development function.
‫Because right now, once we send back that error,
‫we really have no way of then seeing the complete error.
‫Alright, so, getting rid of this to make it more visible.
‫And now that's beautiful.
‫Okay.
‫So let's actually quit it here now
‫so that we can start our production application.
‫So basically running it now in production.
‫And we have a script for that which is called
‫npm run start production.
‫Okay?
‫So if we test this out now
‫then we should no longer see this string here, remember?
‫Because at this point, we do not have any error handling
‫for an invalid tour name like this.
‫Okay?
‫Right?
‫Since we're in production,
‫and it is not an operational error,
‫well, we do not want to see this.
‫And so that's what we just coded up before.
‫And so indeed, this is the more generic error message.
‫Right?
‫But if we then put it back here in the views controller,
‫so if we put this error handling back,
‫then of course, since this here will now be
‫an operational error, then we shall of course get
‫that error string.
‫Because it's always nice
‫to show a friendly message to the user.
‫But as you saw, that actually did not happen.
‫So why is that?
‫Well, we are in the production error.
‫We are at the rendered website.
‫And indeed, we have an operational error.
‫And so ...
‫We have this in place.
‫And so indeed, it should work as we expected.
‫Well, let's just try to log to the console
‫the error dot message
‫just to see if we actually got it at this point.
‫Alright.
‫Reload this guy.
‫And so there is the error.
‫But still, that's very weird.
‫So that's indeed logged the entire error.
‫Very strange.
‫Because for some reason, the message is also not there.
‫So let's run it again in development.
‫So npm start.
‫Alright.
‫And here for some reason, it gets access to this message.
‫So that means that in our views controller,
‫we actually set that message correctly.
‫Run it in production again.
‫So this is the kind of stuff that we don't like, right?
‫So let's take a look at where our error in production
‫is actually created.
‫And that is here.
‫So this error object that we're using here in production
‫is a copy of this error, right?
‫So the one that's coming into this middleware.
‫And so let's actually take a look at both of them
‫in the console.
‫So error dot message.
‫And then also error dot message.
‫So do that again.
‫Okay.
‫So we see that error,
‫so the one that's coming right into our middleware function,
‫does indeed have the message.
‫But then the one that we copy, so error,
‫for some reason does not.
‫And so this trick that we're doing here,
‫for some reason does not copy the message with it,
‫alright?
‫And so let's do a quick fix of that.
‫And let's say that error dot message equals err dot message.
‫Alright?
‫And so that should then fix it, hopefully.
‫Ah, alright.
‫Here we go.
‫Right.
‫So now you see that they are indeed the same.
‫And so that was the problem.
‫Alright?
‫So without this,
‫actually all the errors would not work correctly.
‫So if we put this out here
‫and tried to log in for example, so admin@natours.io.
‫So you see, we also get an undefined error here.
‫Alright.
‫And so that's again because we're in production
‫and our error object didn't correctly copy the message.
‫I'm not sure why I didn't catch this one
‫when we were actually implementing this.
‫But maybe I didn't test it in a thorough enough way.
‫Okay?
‫And anyway, if we try this now,
‫now we then get the correct error message
‫that we're expecting.
‫Alright.
‫Great.
‫So that's solved.
‫And so that actually wraps up this video.
‫So just in conclusion,
‫we now have an error handling strategy
‫that works for development, such as before,
‫and also for production.
‫And then in each of them, we basically have two branches.
‫One sends the error message for the API,
‫which is exactly what we had before,
‫and then we also have now kind of a handler
‫for the rendered website.
‫And so in that case, we render out our error template.
‫Then in production, we also distinguish between
‫rendered website and API.
‫And then just as before,
‫inside of each of these branches,
‫we then also distinguish between
‫the operation errors and the unknown errors.
‫So operational and unknown.
‫And then inside rendered, also operational and unknown.
‫And so for the rendered website,
‫if we have an operational error, so a trusted one,
‫then we send our trusted error message.
‫But in case we do not trust the error,
‫so when we do not know it,
‫then we simply send this generic message back to the user.
‫So, great.
‫Let's quit that here and go back to development
‫and wrap up this lecture.
‫So see you in the next one.