1 00:00:00,980 --> 00:00:03,100 In this video, I want to, very quickly, 2 00:00:03,100 --> 00:00:06,510 refactor the API features that we've implemented 3 00:00:06,510 --> 00:00:08,620 over the last couple of lectures. 4 00:00:08,620 --> 00:00:11,760 Now, this is not only to make our code a bit cleaner, 5 00:00:11,760 --> 00:00:15,000 it's also to make it more modular and more reusable 6 00:00:15,000 --> 00:00:15,913 in the future. 7 00:00:17,290 --> 00:00:20,430 So, right now, we have all this code for the features 8 00:00:20,430 --> 00:00:25,050 that we built before in this getALLTours function, right? 9 00:00:25,050 --> 00:00:26,860 And this looks a bit messy. 10 00:00:26,860 --> 00:00:30,160 It's a bit hard to understand, okay? 11 00:00:30,160 --> 00:00:33,900 And, also imagine that we wanted to use these same features 12 00:00:33,900 --> 00:00:35,010 for another resource. 13 00:00:35,010 --> 00:00:38,250 For example, for the users or, later, for the reviews. 14 00:00:38,250 --> 00:00:40,910 It would be not very practical to, basically, 15 00:00:40,910 --> 00:00:43,300 copy the code from here and use it, then, 16 00:00:43,300 --> 00:00:45,670 in the other resources, right. 17 00:00:45,670 --> 00:00:47,360 And so, what I'm going to do is to, now, 18 00:00:47,360 --> 00:00:50,340 create a class in which I'm going to add one method 19 00:00:50,340 --> 00:00:54,070 for each of these API features or functionalities, 20 00:00:54,070 --> 00:00:55,500 as you might call them as well. 21 00:00:55,500 --> 00:00:56,900 All right? 22 00:00:56,900 --> 00:00:59,906 So, let's go ahead and do that here 23 00:00:59,906 --> 00:01:02,950 and I'm going to do it here, for now, then, later on, 24 00:01:02,950 --> 00:01:05,750 I'm actually going to export it to its own file, 25 00:01:05,750 --> 00:01:08,810 basically, to create a reusable module that we can, 26 00:01:08,810 --> 00:01:11,760 later on, import into other controllers. 27 00:01:11,760 --> 00:01:12,960 All right? 28 00:01:12,960 --> 00:01:16,663 So, class, and I'm calling it APIFeatures. 29 00:01:19,260 --> 00:01:20,093 All right. 30 00:01:21,720 --> 00:01:24,510 Then, we start with our constructor function 31 00:01:24,510 --> 00:01:26,840 and remember that this is the function that gets 32 00:01:26,840 --> 00:01:29,990 automatically called as soon as we create a new object 33 00:01:29,990 --> 00:01:33,070 out of this class, all right. 34 00:01:33,070 --> 00:01:36,830 Now, what do I actually want in these API features? 35 00:01:36,830 --> 00:01:41,090 Actually, I'm going to parse in two variables here, okay? 36 00:01:41,090 --> 00:01:45,962 So the mongoose query and also the queryString 37 00:01:45,962 --> 00:01:47,323 that we get from express. 38 00:01:48,410 --> 00:01:51,420 So, basically, coming from the route, all right. 39 00:01:51,420 --> 00:01:53,490 So that's what we usually have access to 40 00:01:53,490 --> 00:01:56,760 in the req.query, okay. 41 00:01:56,760 --> 00:01:59,780 Now, again, I'm passing the query here because I do not 42 00:01:59,780 --> 00:02:03,110 want to query inside of this class because that would then 43 00:02:03,110 --> 00:02:06,040 bounce this class to the tour resource but, again, 44 00:02:06,040 --> 00:02:08,903 I want this to be as reusable as possible. 45 00:02:10,690 --> 00:02:11,523 All right. 46 00:02:11,523 --> 00:02:14,080 So, what we usually do in this constructor function 47 00:02:14,080 --> 00:02:18,490 is to say this.query equals the query that we got 48 00:02:18,490 --> 00:02:21,480 as an argument and then this.queryString 49 00:02:25,130 --> 00:02:27,890 is equal to the queryString. 50 00:02:27,890 --> 00:02:28,723 Okay? 51 00:02:28,723 --> 00:02:32,490 So very simple, very typical constructor function. 52 00:02:32,490 --> 00:02:35,580 And now, as I mentioned, I'm going to create one method 53 00:02:35,580 --> 00:02:39,313 for each of the functionality, starting with filter. 54 00:02:41,860 --> 00:02:42,693 All right. 55 00:02:42,693 --> 00:02:46,490 And so, let's now go ahead and cut the code from here. 56 00:02:46,490 --> 00:02:49,130 Or, actually, I'm going to copy it and them comment it, 57 00:02:49,130 --> 00:02:52,180 so that I don't do any accidental damage. 58 00:02:52,180 --> 00:02:53,710 So, copy and the comment 59 00:02:55,350 --> 00:02:57,120 and put it right here. 60 00:02:57,120 --> 00:02:59,450 So, a couple of things that we need to change. 61 00:02:59,450 --> 00:03:03,350 First on, request.query is not going to be available 62 00:03:03,350 --> 00:03:04,830 inside of this class. 63 00:03:04,830 --> 00:03:07,250 And so, that's why we actually parsed in the queryString. 64 00:03:07,250 --> 00:03:09,930 And so, this here is going to get replaced 65 00:03:09,930 --> 00:03:11,623 with this.queryString. 66 00:03:13,490 --> 00:03:14,323 Okay? 67 00:03:14,323 --> 00:03:16,450 So, again, this is just basic Javascript. 68 00:03:16,450 --> 00:03:20,260 Has actually nothing to do with Note or Express at all. 69 00:03:20,260 --> 00:03:24,760 Then the rest here is okay but this here is not okay at all. 70 00:03:24,760 --> 00:03:29,340 So I do not want to query the tour directly here, remember, 71 00:03:29,340 --> 00:03:32,170 but instead, I simply want to now add this find 72 00:03:32,170 --> 00:03:34,650 to the query that we already have. 73 00:03:34,650 --> 00:03:37,147 So this.query.find 74 00:03:40,560 --> 00:03:43,763 and so, that will then be this. 75 00:03:45,010 --> 00:03:45,860 All right? 76 00:03:45,860 --> 00:03:47,800 Let's, now, get rid of this. 77 00:03:47,800 --> 00:03:50,370 And before we add any more methods here, 78 00:03:50,370 --> 00:03:52,870 let's actually go ahead and use this class 79 00:03:52,870 --> 00:03:54,833 just so this makes more sense to you. 80 00:03:55,700 --> 00:03:56,533 Okay? 81 00:03:56,533 --> 00:03:58,653 So, how is this actually going to work? 82 00:03:59,890 --> 00:04:02,400 And I'm going to do it all here at the end here 83 00:04:02,400 --> 00:04:04,420 under Execute Query. 84 00:04:04,420 --> 00:04:05,350 All right? 85 00:04:05,350 --> 00:04:07,750 And so, what I can do now is to create a variable 86 00:04:07,750 --> 00:04:09,583 called Features, for example. 87 00:04:12,450 --> 00:04:17,300 And then from here, I will create a new API features object. 88 00:04:17,300 --> 00:04:18,160 Okay? 89 00:04:18,160 --> 00:04:21,560 So, basically, creating an instance of this API features 90 00:04:21,560 --> 00:04:23,870 that will then get stored into Features. 91 00:04:23,870 --> 00:04:26,600 And this here, we'll, then, have access to all the methods 92 00:04:26,600 --> 00:04:29,380 that we're going to define in the class definition. 93 00:04:29,380 --> 00:04:30,360 Okay? 94 00:04:30,360 --> 00:04:33,490 So, remember, in here, we need to pass a query 95 00:04:33,490 --> 00:04:34,980 and the queryString. 96 00:04:34,980 --> 00:04:36,983 So, the query, how do we create one? 97 00:04:38,440 --> 00:04:41,580 Remember, it's Tour.find. 98 00:04:41,580 --> 00:04:45,040 So, there's a query object and so, that's the one that 99 00:04:45,040 --> 00:04:48,010 we parsed into this class and then, of course, 100 00:04:48,010 --> 00:04:52,410 the queryString which is req.query. 101 00:04:52,410 --> 00:04:54,990 Okay, now, on this features here, remember, 102 00:04:54,990 --> 00:04:57,160 we have no access to filter. 103 00:04:57,160 --> 00:05:00,153 And so, let's actually put it right here afterwards. 104 00:05:01,410 --> 00:05:04,070 So, .filter. 105 00:05:04,070 --> 00:05:05,570 Give it a save. 106 00:05:05,570 --> 00:05:07,750 And so, just like this, we're going to run or code 107 00:05:07,750 --> 00:05:10,550 for the API filtering functionality. 108 00:05:10,550 --> 00:05:12,760 Then, here, the next line is, of course, 109 00:05:12,760 --> 00:05:14,970 not going to work because this query here 110 00:05:14,970 --> 00:05:16,670 does not anymore exist. 111 00:05:16,670 --> 00:05:20,947 Instead, what we have now is features.query, right? 112 00:05:22,760 --> 00:05:24,960 So after all this processing now, basically. 113 00:05:26,040 --> 00:05:29,530 Okay, so, right now, after this filter, this.query 114 00:05:29,530 --> 00:05:32,500 will then have this new find method on it. 115 00:05:32,500 --> 00:05:37,310 Okay, and so, again, this is then stored in this.query. 116 00:05:37,310 --> 00:05:39,910 And, later on, we will have all this other methods which, 117 00:05:39,910 --> 00:05:41,930 all of them, will manipulate this.query 118 00:05:42,886 --> 00:05:45,729 so that, in the end, this.query is the query 119 00:05:45,729 --> 00:05:47,620 that we want to execute. 120 00:05:47,620 --> 00:05:48,793 So, just like here. 121 00:05:49,920 --> 00:05:53,800 Okay, so, just like here, we always kept manipulating 122 00:05:53,800 --> 00:05:55,130 the query variable. 123 00:05:55,130 --> 00:05:57,460 We kept adding more and more methods to it 124 00:05:57,460 --> 00:06:00,100 until we, then, executed it by the end. 125 00:06:00,100 --> 00:06:02,530 And so, here, we're doing exactly the same. 126 00:06:02,530 --> 00:06:05,910 We are simply moving the code into all of these methods. 127 00:06:05,910 --> 00:06:06,743 Okay? 128 00:06:06,743 --> 00:06:09,900 Then, in the end, as I said, the query is going to be stored 129 00:06:09,900 --> 00:06:13,290 inside of this property here and so, yeah, 130 00:06:13,290 --> 00:06:14,800 that's where we, then, do the the await 131 00:06:14,800 --> 00:06:16,093 and get back the results. 132 00:06:17,360 --> 00:06:18,220 All right? 133 00:06:18,220 --> 00:06:21,763 Anyway, let's keep moving here and implement the sorting. 134 00:06:22,730 --> 00:06:24,913 So, I'm copying and commenting. 135 00:06:27,300 --> 00:06:32,003 So, filter and the next one is called Sort. 136 00:06:34,030 --> 00:06:35,160 All right. 137 00:06:35,160 --> 00:06:38,510 And so, here again, we need to replace request.query 138 00:06:38,510 --> 00:06:41,013 with this.queryString, okay. 139 00:06:43,455 --> 00:06:46,288 And then, query is now this.query. 140 00:06:47,510 --> 00:06:52,383 So let's get these four in this.query. 141 00:06:56,540 --> 00:06:59,950 Okay, now, the goal here is to basically 142 00:06:59,950 --> 00:07:03,380 chain these methods here one after another. 143 00:07:03,380 --> 00:07:05,340 So let me show that to you here. 144 00:07:05,340 --> 00:07:08,262 So we have filter and then, after that, we want to chain 145 00:07:08,262 --> 00:07:10,253 the sort method. 146 00:07:12,730 --> 00:07:15,820 Now, right now, that is not really going to work 147 00:07:15,820 --> 00:07:20,110 because where are we actually chaining this sort on? 148 00:07:20,110 --> 00:07:24,170 So, basically, we're trying to call it on the result of this 149 00:07:24,170 --> 00:07:27,120 but, right now, what is the result of this? 150 00:07:27,120 --> 00:07:29,840 Well, it's not really anything because this filter method 151 00:07:29,840 --> 00:07:32,840 here doesn't return anything, right? 152 00:07:32,840 --> 00:07:35,460 Now, this piece of code here, of course, returns 153 00:07:35,460 --> 00:07:38,830 the object that has just been created and so, then, 154 00:07:38,830 --> 00:07:41,560 we can chain the filter method on that. 155 00:07:41,560 --> 00:07:44,460 But the filter method, in turn, does not return anything. 156 00:07:44,460 --> 00:07:47,910 And so, at this point, we cannot really call a sort 157 00:07:47,910 --> 00:07:49,630 on the object, right? 158 00:07:49,630 --> 00:07:51,510 And so, the simple solution to that, 159 00:07:51,510 --> 00:07:55,033 and maybe you've done it earlier sometime in your code, 160 00:07:56,520 --> 00:07:58,853 is that we have to now return this. 161 00:08:01,120 --> 00:08:06,103 So, return this and this is simply the entire object, okay? 162 00:08:07,252 --> 00:08:09,723 And the same, then, down here. 163 00:08:11,790 --> 00:08:13,570 So, return this. 164 00:08:13,570 --> 00:08:17,360 In order to, again, return the entire object which, 165 00:08:17,360 --> 00:08:20,530 of course, then has access to these other methods 166 00:08:20,530 --> 00:08:22,493 so that we can, then, call them there. 167 00:08:23,610 --> 00:08:24,443 All right? 168 00:08:25,690 --> 00:08:28,643 So, next up is the limiting. 169 00:08:34,000 --> 00:08:36,150 And I'm going to call this one limitFields. 170 00:08:39,680 --> 00:08:41,340 And that's because all of these methods 171 00:08:41,340 --> 00:08:43,710 will have these verbs as names. 172 00:08:43,710 --> 00:08:47,240 So it's filter, sort, limit, and the paginate 173 00:08:47,240 --> 00:08:48,640 is going to be the next one. 174 00:08:49,870 --> 00:08:53,730 So, again, req.query is now this.queryString 175 00:08:57,649 --> 00:09:00,399 and query here is now this.query. 176 00:09:04,494 --> 00:09:05,327 All right? 177 00:09:08,196 --> 00:09:11,196 Return this and this is not correct. 178 00:09:14,290 --> 00:09:17,123 Okay, and finally, the pagination. 179 00:09:18,490 --> 00:09:19,873 Copy, comment. 180 00:09:25,020 --> 00:09:26,413 So, paginate. 181 00:09:29,770 --> 00:09:31,650 Return this and, of course, we need to 182 00:09:31,650 --> 00:09:34,150 replace these req.query 183 00:09:37,750 --> 00:09:39,187 this.queryString. 184 00:09:39,187 --> 00:09:41,610 And then here, just like before, 185 00:09:41,610 --> 00:09:44,890 it's going to be this.query. 186 00:09:44,890 --> 00:09:47,770 And I just realized that up there, 187 00:09:47,770 --> 00:09:51,040 right in the first method, we didn't do this here. 188 00:09:51,040 --> 00:09:54,560 So, we simply said this.query 189 00:09:54,560 --> 00:09:57,080 and then added the find there. 190 00:09:57,080 --> 00:09:59,190 But then, of course, we need to actually save it 191 00:09:59,190 --> 00:10:01,700 into this query property. 192 00:10:01,700 --> 00:10:03,593 Okay, and so, I forgot that. 193 00:10:04,650 --> 00:10:06,610 And we got some error here. 194 00:10:06,610 --> 00:10:08,280 All right, that doesn't really matter here 195 00:10:08,280 --> 00:10:09,690 at this moment. 196 00:10:09,690 --> 00:10:13,170 Or, actually, it does because this line of code here 197 00:10:13,170 --> 00:10:15,910 is actually in our paginate method. 198 00:10:15,910 --> 00:10:17,490 So let's go there. 199 00:10:17,490 --> 00:10:19,720 And, in fact, I actually wanted to talk to you 200 00:10:19,720 --> 00:10:21,210 about this here. 201 00:10:21,210 --> 00:10:24,350 Because, if you think about it, requesting the next page, 202 00:10:24,350 --> 00:10:27,740 which has zero result, is not really an error. 203 00:10:27,740 --> 00:10:30,852 The fact that there are no results is enough for the user 204 00:10:30,852 --> 00:10:34,900 to realize that, basically, the page that was requested 205 00:10:34,900 --> 00:10:36,660 doesn't contain any data. 206 00:10:36,660 --> 00:10:39,450 So we do not really need an error in this situation. 207 00:10:39,450 --> 00:10:42,933 And so, I'm just going to go ahead and delete all this code. 208 00:10:43,940 --> 00:10:45,430 Okay? 209 00:10:45,430 --> 00:10:47,600 So let me save it now here. 210 00:10:47,600 --> 00:10:49,963 And so now, of course, the error is gone. 211 00:10:53,800 --> 00:10:56,950 And here, we also still have to keep adding 212 00:10:56,950 --> 00:10:58,770 these other methods. 213 00:10:58,770 --> 00:11:02,577 So, limitFields and .paginate. 214 00:11:05,160 --> 00:11:09,360 Give it a save and, again, remember that all of this 215 00:11:09,360 --> 00:11:12,180 chaining here only works because after calling 216 00:11:12,180 --> 00:11:15,420 each of these methods, we always return this. 217 00:11:15,420 --> 00:11:18,800 And this is the object itself which has access 218 00:11:18,800 --> 00:11:21,410 to each of these methods here, making it possible 219 00:11:21,410 --> 00:11:24,640 to chain them just like we have it here. 220 00:11:24,640 --> 00:11:26,860 Okay, so, just to recap: 221 00:11:26,860 --> 00:11:31,040 We are creating a new object of the API features class. 222 00:11:31,040 --> 00:11:33,960 In there, we are parsing a query object 223 00:11:33,960 --> 00:11:37,240 and the query string that's coming from express. 224 00:11:37,240 --> 00:11:38,400 Okay? 225 00:11:38,400 --> 00:11:41,180 Then, in each of these four methods here that we call 226 00:11:41,180 --> 00:11:44,400 one after another, we, basically, manipulate the query. 227 00:11:44,400 --> 00:11:48,010 We keep adding more methods to it just like we've been doing 228 00:11:48,010 --> 00:11:52,160 up here before we did any of this refactoring, right. 229 00:11:52,160 --> 00:11:55,900 So, we keep adding stuff to the query here until the end, 230 00:11:55,900 --> 00:11:59,040 and then, by the end, we simply await the result 231 00:11:59,040 --> 00:12:02,070 that query so that it can come back with all the documents 232 00:12:02,070 --> 00:12:04,210 that were selected, okay? 233 00:12:04,210 --> 00:12:06,580 And that query now lives at features 234 00:12:06,580 --> 00:12:08,640 which is this object here. 235 00:12:08,640 --> 00:12:10,123 So features.query. 236 00:12:11,330 --> 00:12:13,620 Okay, I hope that make sense. 237 00:12:13,620 --> 00:12:17,960 So, before we do anything else, let's go back to Postman 238 00:12:17,960 --> 00:12:20,090 and actually try it out. 239 00:12:20,090 --> 00:12:23,500 And we can try it out right here with this Top-5-cheap route 240 00:12:23,500 --> 00:12:25,650 because that, actually, behind the scenes, 241 00:12:25,650 --> 00:12:29,030 uses all of these API features, right. 242 00:12:29,030 --> 00:12:32,240 So, if I send it, well, it still works. 243 00:12:32,240 --> 00:12:33,763 So that's fantastic. 244 00:12:34,730 --> 00:12:38,823 So let's close it and let me actually save it here. 245 00:12:40,490 --> 00:12:44,453 So, Get Top Five Cheap Tours. 246 00:12:49,220 --> 00:12:51,370 And yeah, I'm going to leave it there at the end. 247 00:12:51,370 --> 00:12:53,763 And now, just here, let's do some testing. 248 00:12:54,790 --> 00:12:58,373 For example, remove the sort, let me leave the limit. 249 00:12:59,570 --> 00:13:02,260 Difficulty, duration, price. 250 00:13:02,260 --> 00:13:04,170 So, I'm going to leave all of this here 251 00:13:04,170 --> 00:13:06,620 just to see if it still works. 252 00:13:06,620 --> 00:13:10,590 And it looks like everything is still working, right. 253 00:13:10,590 --> 00:13:13,110 So these are the exact same results that we got 254 00:13:13,110 --> 00:13:15,500 before our refactoring. 255 00:13:15,500 --> 00:13:17,320 So, great, perfect. 256 00:13:17,320 --> 00:13:20,530 That worked and so, let's, now, actually delete 257 00:13:20,530 --> 00:13:23,950 all this code from here which makes our route handler 258 00:13:23,950 --> 00:13:26,410 so much cleaner, doesn't it? 259 00:13:26,410 --> 00:13:30,840 So, that's so much better, really, it's day and night. 260 00:13:30,840 --> 00:13:31,800 Okay? 261 00:13:31,800 --> 00:13:34,210 Now, the next step is to actually go ahead 262 00:13:34,210 --> 00:13:38,500 and take all this code, cut it and put it into 263 00:13:38,500 --> 00:13:41,700 a new file, so a new module, basically. 264 00:13:41,700 --> 00:13:44,720 Okay, and for that, I'm going to create a new folder here 265 00:13:44,720 --> 00:13:46,563 which I'm going to call Utils. 266 00:13:47,420 --> 00:13:49,713 So that stands, basically, for utilities. 267 00:13:51,010 --> 00:13:53,850 And I'm going to add a couple of stuff in here 268 00:13:53,850 --> 00:13:55,503 over the rest of the course. 269 00:13:57,060 --> 00:13:57,893 Okay? 270 00:13:57,893 --> 00:14:00,050 So this one is going to be called 271 00:14:00,050 --> 00:14:05,050 APIFeatures.js and with a capital F here. 272 00:14:09,430 --> 00:14:10,263 All right? 273 00:14:10,263 --> 00:14:13,621 So, here goes our class and, in the end, 274 00:14:13,621 --> 00:14:17,823 we do a module.exports of this class. 275 00:14:20,040 --> 00:14:21,800 So, nothing new at this point. 276 00:14:21,800 --> 00:14:24,140 Give it a save, close it, 277 00:14:24,140 --> 00:14:27,073 and now, in here, we can require it. 278 00:14:28,147 --> 00:14:30,730 Const APIFeatures then require. 279 00:14:35,980 --> 00:14:38,490 Then we need to move one folder up, 280 00:14:38,490 --> 00:14:41,613 then into Utils and APIFeatures. 281 00:14:43,110 --> 00:14:44,210 Okay? 282 00:14:44,210 --> 00:14:45,313 One more test. 283 00:14:48,010 --> 00:14:51,000 And it's taking some time, and here we go. 284 00:14:51,000 --> 00:14:53,760 Beautiful, that's really just beautiful. 285 00:14:53,760 --> 00:14:57,720 Now, if we create another resource again, 286 00:14:57,720 --> 00:15:00,280 for example, for the users, it's going to be so easy 287 00:15:00,280 --> 00:15:02,630 to drop in this same functionality. 288 00:15:02,630 --> 00:15:06,110 All we're going to have to do is to require this file 289 00:15:06,110 --> 00:15:08,680 and then, basically, do the same as here. 290 00:15:08,680 --> 00:15:11,000 Or maybe, in that case, we don't even want 291 00:15:11,000 --> 00:15:14,040 to have this sorting ability or we don't want 292 00:15:14,040 --> 00:15:17,140 to have the filtering ability and then, all we have to do 293 00:15:17,140 --> 00:15:19,440 is to simply take out this line of code. 294 00:15:19,440 --> 00:15:21,680 And then, like magic, it'll only do 295 00:15:21,680 --> 00:15:23,280 these three functionalities 296 00:15:23,280 --> 00:15:25,810 or these three features, okay. 297 00:15:25,810 --> 00:15:27,890 And so, that's really great. 298 00:15:27,890 --> 00:15:29,630 I hope you can see the value of this 299 00:15:29,630 --> 00:15:33,353 and, yeah, I'm really happy with this result.