‫In this video, I want to, very quickly,
‫refactor the API features that we've implemented
‫over the last couple of lectures.
‫Now, this is not only to make our code a bit cleaner,
‫it's also to make it more modular and more reusable
‫in the future.
‫So, right now, we have all this code for the features
‫that we built before in this getALLTours function, right?
‫And this looks a bit messy.
‫It's a bit hard to understand, okay?
‫And, also imagine that we wanted to use these same features
‫for another resource.
‫For example, for the users or, later, for the reviews.
‫It would be not very practical to, basically,
‫copy the code from here and use it, then,
‫in the other resources, right.
‫And so, what I'm going to do is to, now,
‫create a class in which I'm going to add one method
‫for each of these API features or functionalities,
‫as you might call them as well.
‫All right?
‫So, let's go ahead and do that here
‫and I'm going to do it here, for now, then, later on,
‫I'm actually going to export it to its own file,
‫basically, to create a reusable module that we can,
‫later on, import into other controllers.
‫All right?
‫So, class, and I'm calling it APIFeatures.
‫All right.
‫Then, we start with our constructor function
‫and remember that this is the function that gets
‫automatically called as soon as we create a new object
‫out of this class, all right.
‫Now, what do I actually want in these API features?
‫Actually, I'm going to parse in two variables here, okay?
‫So the mongoose query and also the queryString
‫that we get from express.
‫So, basically, coming from the route, all right.
‫So that's what we usually have access to
‫in the req.query, okay.
‫Now, again, I'm passing the query here because I do not
‫want to query inside of this class because that would then
‫bounce this class to the tour resource but, again,
‫I want this to be as reusable as possible.
‫All right.
‫So, what we usually do in this constructor function
‫is to say this.query equals the query that we got
‫as an argument and then this.queryString
‫is equal to the queryString.
‫Okay?
‫So very simple, very typical constructor function.
‫And now, as I mentioned, I'm going to create one method
‫for each of the functionality, starting with filter.
‫All right.
‫And so, let's now go ahead and cut the code from here.
‫Or, actually, I'm going to copy it and them comment it,
‫so that I don't do any accidental damage.
‫So, copy and the comment
‫and put it right here.
‫So, a couple of things that we need to change.
‫First on, request.query is not going to be available
‫inside of this class.
‫And so, that's why we actually parsed in the queryString.
‫And so, this here is going to get replaced
‫with this.queryString.
‫Okay?
‫So, again, this is just basic Javascript.
‫Has actually nothing to do with Note or Express at all.
‫Then the rest here is okay but this here is not okay at all.
‫So I do not want to query the tour directly here, remember,
‫but instead, I simply want to now add this find
‫to the query that we already have.
‫So this.query.find
‫and so, that will then be this.
‫All right?
‫Let's, now, get rid of this.
‫And before we add any more methods here,
‫let's actually go ahead and use this class
‫just so this makes more sense to you.
‫Okay?
‫So, how is this actually going to work?
‫And I'm going to do it all here at the end here
‫under Execute Query.
‫All right?
‫And so, what I can do now is to create a variable
‫called Features, for example.
‫And then from here, I will create a new API features object.
‫Okay?
‫So, basically, creating an instance of this API features
‫that will then get stored into Features.
‫And this here, we'll, then, have access to all the methods
‫that we're going to define in the class definition.
‫Okay?
‫So, remember, in here, we need to pass a query
‫and the queryString.
‫So, the query, how do we create one?
‫Remember, it's Tour.find.
‫So, there's a query object and so, that's the one that
‫we parsed into this class and then, of course,
‫the queryString which is req.query.
‫Okay, now, on this features here, remember,
‫we have no access to filter.
‫And so, let's actually put it right here afterwards.
‫So, .filter.
‫Give it a save.
‫And so, just like this, we're going to run or code
‫for the API filtering functionality.
‫Then, here, the next line is, of course,
‫not going to work because this query here
‫does not anymore exist.
‫Instead, what we have now is features.query, right?
‫So after all this processing now, basically.
‫Okay, so, right now, after this filter, this.query
‫will then have this new find method on it.
‫Okay, and so, again, this is then stored in this.query.
‫And, later on, we will have all this other methods which,
‫all of them, will manipulate this.query
‫so that, in the end, this.query is the query
‫that we want to execute.
‫So, just like here.
‫Okay, so, just like here, we always kept manipulating
‫the query variable.
‫We kept adding more and more methods to it
‫until we, then, executed it by the end.
‫And so, here, we're doing exactly the same.
‫We are simply moving the code into all of these methods.
‫Okay?
‫Then, in the end, as I said, the query is going to be stored
‫inside of this property here and so, yeah,
‫that's where we, then, do the the await
‫and get back the results.
‫All right?
‫Anyway, let's keep moving here and implement the sorting.
‫So, I'm copying and commenting.
‫So, filter and the next one is called Sort.
‫All right.
‫And so, here again, we need to replace request.query
‫with this.queryString, okay.
‫And then, query is now this.query.
‫So let's get these four in this.query.
‫Okay, now, the goal here is to basically
‫chain these methods here one after another.
‫So let me show that to you here.
‫So we have filter and then, after that, we want to chain
‫the sort method.
‫Now, right now, that is not really going to work
‫because where are we actually chaining this sort on?
‫So, basically, we're trying to call it on the result of this
‫but, right now, what is the result of this?
‫Well, it's not really anything because this filter method
‫here doesn't return anything, right?
‫Now, this piece of code here, of course, returns
‫the object that has just been created and so, then,
‫we can chain the filter method on that.
‫But the filter method, in turn, does not return anything.
‫And so, at this point, we cannot really call a sort
‫on the object, right?
‫And so, the simple solution to that,
‫and maybe you've done it earlier sometime in your code,
‫is that we have to now return this.
‫So, return this and this is simply the entire object, okay?
‫And the same, then, down here.
‫So, return this.
‫In order to, again, return the entire object which,
‫of course, then has access to these other methods
‫so that we can, then, call them there.
‫All right?
‫So, next up is the limiting.
‫And I'm going to call this one limitFields.
‫And that's because all of these methods
‫will have these verbs as names.
‫So it's filter, sort, limit, and the paginate
‫is going to be the next one.
‫So, again, req.query is now this.queryString
‫and query here is now this.query.
‫All right?
‫Return this and this is not correct.
‫Okay, and finally, the pagination.
‫Copy, comment.
‫So, paginate.
‫Return this and, of course, we need to
‫replace these req.query
‫this.queryString.
‫And then here, just like before,
‫it's going to be this.query.
‫And I just realized that up there,
‫right in the first method, we didn't do this here.
‫So, we simply said this.query
‫and then added the find there.
‫But then, of course, we need to actually save it
‫into this query property.
‫Okay, and so, I forgot that.
‫And we got some error here.
‫All right, that doesn't really matter here
‫at this moment.
‫Or, actually, it does because this line of code here
‫is actually in our paginate method.
‫So let's go there.
‫And, in fact, I actually wanted to talk to you
‫about this here.
‫Because, if you think about it, requesting the next page,
‫which has zero result, is not really an error.
‫The fact that there are no results is enough for the user
‫to realize that, basically, the page that was requested
‫doesn't contain any data.
‫So we do not really need an error in this situation.
‫And so, I'm just going to go ahead and delete all this code.
‫Okay?
‫So let me save it now here.
‫And so now, of course, the error is gone.
‫And here, we also still have to keep adding
‫these other methods.
‫So, limitFields and .paginate.
‫Give it a save and, again, remember that all of this
‫chaining here only works because after calling
‫each of these methods, we always return this.
‫And this is the object itself which has access
‫to each of these methods here, making it possible
‫to chain them just like we have it here.
‫Okay, so, just to recap:
‫We are creating a new object of the API features class.
‫In there, we are parsing a query object
‫and the query string that's coming from express.
‫Okay?
‫Then, in each of these four methods here that we call
‫one after another, we, basically, manipulate the query.
‫We keep adding more methods to it just like we've been doing
‫up here before we did any of this refactoring, right.
‫So, we keep adding stuff to the query here until the end,
‫and then, by the end, we simply await the result
‫that query so that it can come back with all the documents
‫that were selected, okay?
‫And that query now lives at features
‫which is this object here.
‫So features.query.
‫Okay, I hope that make sense.
‫So, before we do anything else, let's go back to Postman
‫and actually try it out.
‫And we can try it out right here with this Top-5-cheap route
‫because that, actually, behind the scenes,
‫uses all of these API features, right.
‫So, if I send it, well, it still works.
‫So that's fantastic.
‫So let's close it and let me actually save it here.
‫So, Get Top Five Cheap Tours.
‫And yeah, I'm going to leave it there at the end.
‫And now, just here, let's do some testing.
‫For example, remove the sort, let me leave the limit.
‫Difficulty, duration, price.
‫So, I'm going to leave all of this here
‫just to see if it still works.
‫And it looks like everything is still working, right.
‫So these are the exact same results that we got
‫before our refactoring.
‫So, great, perfect.
‫That worked and so, let's, now, actually delete
‫all this code from here which makes our route handler
‫so much cleaner, doesn't it?
‫So, that's so much better, really, it's day and night.
‫Okay?
‫Now, the next step is to actually go ahead
‫and take all this code, cut it and put it into
‫a new file, so a new module, basically.
‫Okay, and for that, I'm going to create a new folder here
‫which I'm going to call Utils.
‫So that stands, basically, for utilities.
‫And I'm going to add a couple of stuff in here
‫over the rest of the course.
‫Okay?
‫So this one is going to be called
‫APIFeatures.js and with a capital F here.
‫All right?
‫So, here goes our class and, in the end,
‫we do a module.exports of this class.
‫So, nothing new at this point.
‫Give it a save, close it,
‫and now, in here, we can require it.
‫Const APIFeatures then require.
‫Then we need to move one folder up,
‫then into Utils and APIFeatures.
‫Okay?
‫One more test.
‫And it's taking some time, and here we go.
‫Beautiful, that's really just beautiful.
‫Now, if we create another resource again,
‫for example, for the users, it's going to be so easy
‫to drop in this same functionality.
‫All we're going to have to do is to require this file
‫and then, basically, do the same as here.
‫Or maybe, in that case, we don't even want
‫to have this sorting ability or we don't want
‫to have the filtering ability and then, all we have to do
‫is to simply take out this line of code.
‫And then, like magic, it'll only do
‫these three functionalities
‫or these three features, okay.
‫And so, that's really great.
‫I hope you can see the value of this
‫and, yeah, I'm really happy with this result.