So in this lecture, we're gonna fix
the request 404 error that we saw happening
in the last lecture.
And so as we saw in the last video, the problem here
is that during the fetch, there was a 404 error,
which is because our API couldn't find any country
with this name.
But still, even though there
was obviously a big problem with this request,
the fetch function still did not reject in this case,
and by the way, many people,
and that includes myself think that in this case,
the promise should actually be rejected right away,
but again, it just doesn't,
and so we will have to do it manually.
So to see what happens here, let's go back
to this first then handler here, which gets access
to the response immediately.
So without even the data.
So here, I'm adding back a block,
and let's take a look at the response here.
And also, since we added back the block,
we now need to return this explicitly.
So again, for now, we are just taking a look
at the response object here.
And so here it is,
and so right here, you can see
that the Ok property is set to false.
And so the reason for that,
is, of course, the status code 404.
Now, when the request goes well,
and so that's what's gonna happen when I click here.
So then if we take a look at the response, Ok is true,
and that's because status is 200.
And so 200 literally stands for Ok.
So we can now use the fact
that this response has the Ok property set to false
to basically reject the promise,
or selves manually, now, right,
so we can do that by creating a new error.
So we can say, if there is no response, dot Ok,
or in other words, if response dot Ok is false,
then we right, throw new error,
and then here we can define an error message.
So let's write a very logical message here,
which is country not found.
So this is the real error message that we want to see here,
and of course, not this one here
with cannot read property of undefined.
And here, we can then also take the status code,
and display it as well.
So this 404, in this case, let's just wrap it here
into parenthesis, and Ok.
So this is something that we never did before.
So let's analyze what happens here.
So we create the new error
by using again, this constructor function, basically,
and then we pass in a message, which is gonna be
the error message, then we use the throw keyword here,
which will immediately terminate the current function.
So just like return does it.
Now the effect of creating,
and throwing an error in any of these then methods
is that the promise will immediately reject.
So basically, the promise returned
by this then handler here will be a rejected promise.
And that rejection will then propagate all the way down
to the catch handler, which we already have set up here.
And so now, if we will try to reload this,
and actually, let's do that.
So now this error message that we created here,
so that's country not found 404.
So exactly this, this is exactly the rejection
that we created here by creating this new error.
All right, so again, any error that happens
in any of the callback functions here,
so in any then handler, will immediately terminate
that then handler and will propagate down
to the catch method here.
And then in there, we handle that error,
and so therefore, that's why we then see
the error here displayed.
So that error dot message is exactly that message
that we pass into the error here.
And in fact, the same is true for any other error.
So before we had this,
the error that we saw was this one here,
and that's because somewhere
in the render country function, we are trying to read
the flag from the data that we received,
but the data that we received did not contain this flag.
And so therefore it created this error,
and then that error caused the rejection of the promise,
which was then one more time handled down here, okay.
So again, any error will cause any promise to reject,
but here, we are simply creating our own error
to basically reject the promise on purpose,
so that we can then handle
that error down here in the chain,
so in this catch method, all right.
But now, you might be wondering,
why should we even bother handle all these errors?
Isn't that just a bunch of work and a waste of time?
Well, first, handling these errors is the only way
in which we can actually display an error message like this
on the screen for the user,
but even more important, it's just a really bad practice
to leave these rejected promises,
hanging around without handling them.
So don't do that, always use catch,
and if necessary, you can also use finally, okay.
And now, again, what if there
was no error here in this promise?
So if we got no problem in this one here,
but then we get a problem in the second fetch.
So let's say that, we don't do this,
and so we have a reasonable country,
which is Portugal when we click on the button,
but then here, let's say that the neighbor is not this one,
but this country code, which I'm sure does not exist.
And so now there is gonna be a rejection
in this promise, right.
So we get another error here.
In this case, it's a 400 error, which means something else,
but in any case, the error is not handled.
So we now need to go ahead,
and copy this code here, also into this then handler.
Let's actually do that, even though we know
it's a bad practice, and we need to fix this later.
Okay, and so now we get the error message that we want.
So again, country not found,
and this time with the code 400.
But now, of course, we have all this duplicate code here.
So we shouldn't have this here.
And in fact, even all of this is kind of repetitive.
It's really, if you think about it
the same code as this one.
And so now, I think that it's a good time
to actually create ourselves a really nice helper function.
And this helper function will wrap up
the fetch the error handling,
and also the conversion to JSON,
because in my opinion, it's really a bit cumbersome
to having to do all these steps all the time.
So having the fetch, and then having to convert
that response to JSON,
and only then being able to handle it, right.
So instead, we will basically encapsulate all of this here
into one nice function, so let's do that,
and I'm gonna call it getJSON.
So basically, because it gets data,
and it immediately converts to JSON.
Now, what do we need here as parameters?
Well, for sure, we need the URL,
and so for now, that's okay, here.
So let's get, or actually, we can just write it.
So what we want here is fetch,
and then the URL that we pass into the function,
and then on that we want to call then,
and then basically with all of this.
So let's grab it here.
And that, of course, we are missing
the callback function itself here,
so that should end somewhere here,
and, well, apparently, it doesn't.
Maybe like this, and yes, that's correct.
All right, now in order
to actually make this function her really generic,
we do not want to hard code the error message,
but instead, we want to pass the message in.
So let's say error message,
and we can set a nice default value.
So let's say something went wrong,
which again is very generic,
and so here, inside of this, we then want
the error message that we passed in,
and along with response dot status.
Okay, and now all we need to do is to return all of this.
And so like this,
this getJSON function will actually return a promise.
And so this is then just like any other promise
that we can call here in our chain,
and basically replace all of this.
So just so we can keep this code, I'm gonna copy it.
And so you can then keep this code here,
basically as a reference for when you need
to study it again, okay.
But again, I will now go ahead and take everything
that we just nicely encapsulated into our getJSON function,
and simply replace this.
So getJSON, and then the URL is this one,
and the error message is country not found, now, right.
And so now, we can take away all of this.
So this is already in our get JSON function,
and so we don't need this.
All right, and now the same down here.
Instead of fetch, we can get JSON,
and then we don't need this done here.
And again, the error message is country not found.
Okay, and so let's get rid of this, now, right.
So let's check here,
and indeed, we get, again, country not found
with code 400 because of this one.
So that's working great,
but there's still one more thing
that we need to do, which is to handle the fact
that sometimes there might be no neighbor.
So right now, what we're doing here when there
is no neighbor, is to simply return,
but as I mentioned before, that doesn't really do anything.
So let me just try here, a country that has no neighbors.
So let's say Australia, because that is an island,
and so here again, we get cannot read property flag
of undefined, and so that is happening,
because it is trying to render a country that doesn't exist.
Okay, so again, it's because of this neighbor,
and just to make sure, to illustrate my point here,
you see that the neighbor is indeed undefined.
And so what we want to do here
is to simply just like before, throw a new error
that will then get caught down here
in our catch handler, right.
So throw new error, no neighbor, found,
and that's a lot better.
So now, this is a real error message
that actually makes sense to the user.
Of course, this could be all a bit better,
but this is just a demonstration anyway,
but I think that
it nicely demonstrate how we can create a real error message
that does actually make sense.
And again, that is super important
for any user interface that you're building,
because in web applications like this very small one,
errors will happen, that is just guaranteed,
and so your application needs to be ready,
and needs to be prepared for that.
All right, so let's now quickly recap here.
And I think that the big takeaway from this lecture
is that whenever we want to create some error
that we want to handle down here,
in the catch handler, all we need to do is to throw,
and create a new error, just like we did here.
And of course, we can do that for multiple reasons.
So in this case, here, we did it simply
because in the situation, no neighbor can be found.
And so that is a good reason to display an error message
on the user interface,
and since we do that down here in our error handler,
the best way of doing that is to indeed throw an error.
And remember that this works,
because throwing an error inside of this callback function
of this then method will immediately reject this promise.
And so then that rejected promise will travel down
the chain until it is eventually caught somewhere.
So again, in this case, it is right here
in this catch handler.
So when working with real applications
in the real world, really make sure
to keep this technique in mind,
because it's really important.