Instructor: In this video,
we're gonna be building a handler factory function
in order to delete review documents,
but also documents from all the other collections,
all with one simple function.
So, as I mentioned right at the beginning of this section,
adding very similar handlers to all of our controllers
will create a lot of duplicate code, right?
Because all these update handlers,
or all these delete handlers,
or all these create handlers,
they really all just look basically the same, right?
Also, imagine that we wanted to change
like some https status code or status message.
Then we would have to go into each and every controller
and then change all the handlers in there.
And so, instead of manually writing all these handlers,
why not simply create a factory function
that's gonna return these handlers for us?
So, a factory function is exactly that.
It's a function that returns another function,
and in this case our handler function.
So, for deleting, for creating, for updating,
and also for reading resources.
Okay and I know that this whole concept can be a bit complex
to wrap your head around,
and that's the reason why I left this
for the later part of this course.
But now, I believe that you're actually ready
to implement this kinda stuff.
So this kind of logic is what every advanced
JavaScript developer should be able to implement,
and so again I believe that at this point in the course
you're really ready to start using advanced concept
like this, all right.
But enough talk, let me now show you how it actually works
by using the delete handler as a first example.
And so actually we have one in the tour controller,
and so let's go ahead and copy that one,
so delete tour.
Okay, so I copied it basically
as a template for us to follow.
So let's create a new file, and I'm going to do that
in the controllers.
All right,
so handler...
factory.js.
And I'm doing this is the controllers folder,
well because the functions that we're gonna write here
will basically return controllers.
And so for me it makes a lot of sense
that you put them here.
So let's just copy this part here,
just to keep it as a reference.
So again the goal here is to basically create a function,
which will then return a function
that looks like this one here.
But of course not only for the tour,
but for every single model that we have in our application
and that we might have in the future.
So this function needs to be prepared for that,
and so what that means is that inside the factory function,
we will pass in the model, all right.
So let's call this one deleteOne.
And it's called like this, again,
because this function is not only going
to work to delete tours,
but also to delete reviews and users
and in the future some other documents
that we might also have.
So as I was saying in the beginning,
we will pass the model into this function.
So we pass the model and then we create a new function,
and that function will right away
then return our async function,
so basically all of this or async handler function.
Okay, and so now all we need to do is to actually change
from the specific tool model to the more generic model.
Then here we will also change this from tour to the document
because again, we will not know what kinda document is this.
So this function will not really know if it is a tour,
or if it is a review, or a user.
And so we need to take the tour out of all of this,
and that's actually it.
So this basically the generalization
of this specific function, which worked only for tours,
and now this new one works for every model.
What we also need to do here is to import this catchAsync
and also this AppError.
So catchAsync...
and I believe it's in the utilities folder.
And then, not AppError but catchAsync.
Then duplicate this here,
AppError, and this here is uppercase.
Give it a save, and we're now ready
to actually test this out.
So this is how it's going to work,
first of all we need to import that handler factory.
And so let's say,
and I'm simply going to call it factory here.
So require, and it's in the same folder,
so handler factory.
All right and so let's comment this one here out,
or actually not all of this.
Yeah or actually we can comment it out,
and so the new exports.deletes tour will be...
factory.deleteOne and then pass in the model,
which is tour.
And that's it, that's all we need to do.
So just to recap very quickly here,
so we call this deleteOne function,
then in there we pass the model,
and so what's going to happen is that this function
will then right away return this handler function
that we had before.
Simply the specific model, which before was the tour,
is now going to be replaced with the one
that we passed into the function.
And by the way this works because of JavaScript closures,
which is just a fancy way of saying
that this inner function here will get access
to the variables of the outer function
even after the outer has already returned.
So calling this function here
will then return another function,
which will then sit here and wait until it is finally called
as soon as we hit the corresponding route.
And so let's now try exactly that.
So delete tour,
okay, and let's choose a tour
that we don't really need here for now.
So let's say...
now let's say here The Snow Adventurer
'cause it also doesn't have any reviews.
So let's send that,
oh and now we don't have permission to preform the action,
and that's because we're not logged in as an admin.
So let's try that,
and so this is the admin that we need to be logged in.
Okay, so that's done.
And so now this should work, and indeed it did work.
And so that's proof that our factory function
is really doing it's job.
Okay 'cause if you now come back here,
we had 10 results and so now we should only get nine,
so perfect.
And now the goal is to be able to use this
in each and every single controller.
So let's copy this here
and go to the reviews.
Oh and of course we need it up here,
right in the beginning, now right,
and so now export.deleteReview
is equal to factory.deleteOne
with the review model.
And that's it, that's all we need to do
in order to implement the delete handler.
Now of course we also need to specify the route handler.
Now of course we need to specify the route itself,
and so let's do that here as well.
So router.route
because here we actually need the ID parameter.
And now delete is simply reviewController.deleteReview,
and I'm not messing with the permission here,
neither with authentication
because for now I just want to make this work
and worry about that stuff a bit later in this section.
Okay, so let's close this stuff up here.
So get all reviews,
all right,
let's save this and this one as well.
So that now we can start with a blank sheet here
and let's just start by getting all reviews,
so that we can now delete one.
And so let's delete, well just this one.
Okay, now we also need of course this,
and then the delete http method.
We need no authorization at this point,
so let's just send it.
And indeed no content, so 204.
And if we now get all the reviews,
then we should be back to having just three.
Yep, that works and so let's move on to the next one.
Okay so reviews, reviews.
Let's get this line of code here and now finally add it
to the user controller as well.
All right, and of course all of this,
I understand it's a bit confusing now messing
with all of these different files,
but we just need to do it once and then we're done
with all that confusion.
So here we already had the export.deleteUser,
now all we need to do is to then call our factory function,
so deleteOne and then the user.
Now only the administrator should later be able
to actually delete users because remember that
when the user deletes himself,
then they will not actually get deleted
but only active will be set to false.
But the administrator on the other hand
is really gonna be able to delete the user effectively
from the database.
But again, we're going to worry
about that permission stuff a bit later.
For now, let's check in the userRoutes
if the route is actually implemented,
and yeah it is down here.
And so since we now implemented this,
let's also test it here again also on Postman.
So first let's save this one.
So...
delete review,
and now let's simply copy this
into yet another route.
So delete and then one user,
but I'm actually not really going to do it now.
All I want is to just get some random ID.
Or actually let's just create a new user,
so basically sign up, and then delete that one right away.
So hello, like this.
Get all users, and then it's this guy here.
And so let's delete him right away,
so we send, we get 204 no content.
And of course, now he should be gone.
Now if we try to see her again,
so basically trying to delete a user
that is no longer there, we should get an error.
So let's take a look, and indeed no document found
with that ID.
And so this means that in our factory function,
so right here, all of this the AppError and the catchAsync,
all of that is still intact.
So everything still works just the same as before.
Now so that was also important to test here.
Let's just quickly save this here as well,
so each and every single endpoint that we're implementing,
I'm also adding it here into Postman
because a bit later we will then actually be able
to actually create some API documentation
based on all of this that we have saved here in Postman.
So that's yet another handy feature of this application.
So we have delete the current user,
and again that's different from just deleting the user
because this one here is for administration
and this one is for the currently logged in user,
so very different.
Okay, so this was our first factory function
only for deleting and only for you to understand
the concept itself.
Next up, we're then gonna implement factory functions
for updating and for creating documents.