1 00:00:00,920 --> 00:00:02,913 So as I mentioned in the last video 2 00:00:02,913 --> 00:00:05,243 there are three types of errors 3 00:00:05,243 --> 00:00:07,525 that might be created by Mongoose 4 00:00:07,525 --> 00:00:10,520 in which we need to mark as operational errors 5 00:00:10,520 --> 00:00:13,700 so that we can send back meaningful error messages 6 00:00:13,700 --> 00:00:15,383 to clients in production. 7 00:00:16,890 --> 00:00:21,290 And let's now start by simulating these three errors, okay? 8 00:00:21,290 --> 00:00:25,263 So the first one is when we try an invalid ID here, 9 00:00:26,240 --> 00:00:28,180 so simply something like this, 10 00:00:28,180 --> 00:00:30,950 and so Mongoose will not be able to convert this 11 00:00:30,950 --> 00:00:33,427 into a MongoDB ID, remember that. 12 00:00:33,427 --> 00:00:36,799 And so this is the error that we get right now, 13 00:00:36,799 --> 00:00:39,650 and actually, here you can see all the kind of stuff 14 00:00:39,650 --> 00:00:42,950 that we defined we wanted to see in productions. 15 00:00:42,950 --> 00:00:47,010 So the entire error object, then the error message, 16 00:00:47,010 --> 00:00:50,590 and also the complete stack, okay? 17 00:00:50,590 --> 00:00:53,180 And so this is a perfect example 18 00:00:53,180 --> 00:00:54,500 of an operational error. 19 00:00:54,500 --> 00:00:57,160 So this is something that might very well happen, 20 00:00:57,160 --> 00:01:00,060 and so we need to send back a meaningful response 21 00:01:00,060 --> 00:01:02,380 in order to handle this error. 22 00:01:02,380 --> 00:01:05,590 And this is a perfect example of an operational error 23 00:01:05,590 --> 00:01:09,260 that is very likely to at some point happen to a client, 24 00:01:09,260 --> 00:01:11,740 and so, we need to handle it as one, alright? 25 00:01:11,740 --> 00:01:14,607 So, basically by sending a nice error message 26 00:01:14,607 --> 00:01:16,690 instead of something like this, 27 00:01:16,690 --> 00:01:20,181 which doesn't mean anything to any client, right? 28 00:01:20,181 --> 00:01:22,500 Okay, so the goal here again 29 00:01:22,500 --> 00:01:26,120 will be to basically mark this error as operational, 30 00:01:26,120 --> 00:01:28,880 and create a meaningful message, alright? 31 00:01:28,880 --> 00:01:30,580 But before we can do that, let's take a look 32 00:01:30,580 --> 00:01:32,620 at the other two Mongoose errors 33 00:01:32,620 --> 00:01:36,260 that we also will have to mark as operational, okay? 34 00:01:36,260 --> 00:01:38,457 So, let's Create a New Tour, 35 00:01:38,457 --> 00:01:43,236 and what I'm gonna do is to create a duplicate name. 36 00:01:43,236 --> 00:01:46,210 So, let's just copy this one here. 37 00:01:50,347 --> 00:01:52,503 And I think all the values here are correct, 38 00:01:52,503 --> 00:01:54,780 so let's try this now. 39 00:01:54,780 --> 00:01:58,520 And indeed, here we get the error that we already know, 40 00:01:58,520 --> 00:02:00,210 which is duplicate key error 41 00:02:00,210 --> 00:02:01,960 because we already have a tour, 42 00:02:01,960 --> 00:02:05,740 or a document with the name of Forest Hiker, okay? 43 00:02:05,740 --> 00:02:07,440 So again, this is an error 44 00:02:07,440 --> 00:02:09,420 that is going to happen at some point, 45 00:02:09,420 --> 00:02:10,720 and again, it doesn't have 46 00:02:10,720 --> 00:02:13,650 a very meaningful error message, right? 47 00:02:13,650 --> 00:02:16,243 And so again, we need to change that. 48 00:02:17,200 --> 00:02:19,954 Then the third one is also kind of about validation, 49 00:02:19,954 --> 00:02:23,980 and so let's do that here in Update Tour. 50 00:02:23,980 --> 00:02:27,835 So, let's say that we want to have a ratingsAverage of six, 51 00:02:27,835 --> 00:02:30,700 which we know is invalid, right? 52 00:02:30,700 --> 00:02:33,430 Because we said that the max of ratingsAverage 53 00:02:33,430 --> 00:02:34,960 could be five. 54 00:02:34,960 --> 00:02:36,720 So let's see, and indeed, 55 00:02:36,720 --> 00:02:40,891 we get this ValidationError, right? 56 00:02:40,891 --> 00:02:43,300 So it's called a ValidationError, 57 00:02:43,300 --> 00:02:47,600 and it has this errors object with all the errors. 58 00:02:47,600 --> 00:02:49,400 Let's actually put another one here. 59 00:02:51,377 --> 00:02:53,183 So let's say difficulty, 60 00:02:55,229 --> 00:02:57,110 and then something else, 61 00:02:57,110 --> 00:02:59,981 so one that's not easy, medium, or difficult, 62 00:02:59,981 --> 00:03:03,540 and so now we get these two objects here. 63 00:03:03,540 --> 00:03:08,090 Ones for the ratings, and one for the difficulty, alright? 64 00:03:08,090 --> 00:03:09,800 So these are the three errors 65 00:03:09,800 --> 00:03:11,740 that we're gonna mark as operational, 66 00:03:11,740 --> 00:03:14,110 starting with this first one, 67 00:03:14,110 --> 00:03:17,540 so basically, the CastError type, okay? 68 00:03:17,540 --> 00:03:20,250 So, let's go back here, and we're gonna do that here, 69 00:03:20,250 --> 00:03:24,260 again, because we only want to do this in production, okay? 70 00:03:24,260 --> 00:03:26,570 In development, we don't care about any of this. 71 00:03:26,570 --> 00:03:28,576 All we want to do is see our errors 72 00:03:28,576 --> 00:03:30,910 so that we can basically fix them, 73 00:03:30,910 --> 00:03:33,220 but in production, this is where we want to send 74 00:03:33,220 --> 00:03:36,110 the meaningful error messages to the clients. 75 00:03:36,110 --> 00:03:40,690 So, let's say if err.name 76 00:03:40,690 --> 00:03:45,690 is equal to CastError, 77 00:03:45,980 --> 00:03:48,400 and so that's how we're going to identify 78 00:03:48,400 --> 00:03:51,000 this type of error here that we just talked about, 79 00:03:51,000 --> 00:03:55,300 because it has the name of CastError, alright? 80 00:03:55,300 --> 00:03:57,564 So if err.name is CastError, 81 00:03:57,564 --> 00:04:02,230 well then we're gonna call a special function 82 00:04:02,230 --> 00:04:03,880 that we're gonna create in a second, 83 00:04:03,880 --> 00:04:06,097 which is called handleCastError. 84 00:04:10,750 --> 00:04:14,290 And then I'm also gonna say here DB for database, 85 00:04:14,290 --> 00:04:18,320 so that we know that this is related to our database, okay? 86 00:04:18,320 --> 00:04:19,920 And this is how it's gonna work. 87 00:04:19,920 --> 00:04:21,470 We're gonna pass the error 88 00:04:21,470 --> 00:04:23,683 that Mongoose created into this function, 89 00:04:24,720 --> 00:04:27,070 so just like this, and this will then return 90 00:04:27,070 --> 00:04:30,840 a new error created with out AppError class, okay? 91 00:04:30,840 --> 00:04:33,930 And that error will then be marked as operational, 92 00:04:33,930 --> 00:04:36,120 because remember, all our AppErrors 93 00:04:36,120 --> 00:04:38,030 have the is operational properties 94 00:04:38,030 --> 00:04:40,523 set to two automatically, right? 95 00:04:41,820 --> 00:04:46,390 So this will return an error, and so, let's save that, okay? 96 00:04:46,390 --> 00:04:49,260 And so were saving that in err. 97 00:04:49,260 --> 00:04:51,050 Now it's not a good practice at all 98 00:04:51,050 --> 00:04:54,700 to override the arguments of a function, okay? 99 00:04:54,700 --> 00:04:57,930 So error comes from this middle err function, right? 100 00:04:57,930 --> 00:05:01,020 So, from here, and so instead of doing that, 101 00:05:01,020 --> 00:05:03,217 I will actually create a hard copy 102 00:05:03,217 --> 00:05:06,516 of that error object, okay? 103 00:05:06,516 --> 00:05:09,760 So let, and I'm using let, and not const, 104 00:05:09,760 --> 00:05:11,700 because we will of course reassign 105 00:05:11,700 --> 00:05:14,043 a new error then, later here. 106 00:05:15,490 --> 00:05:18,820 So, let's call this one error instead of just err, 107 00:05:18,820 --> 00:05:22,250 which is the normal name of errors in Express. 108 00:05:22,250 --> 00:05:24,710 And so again, we're gonna use our trick 109 00:05:24,710 --> 00:05:29,133 where we use destructuring of the original error, okay? 110 00:05:30,930 --> 00:05:34,257 And so, from now on, we will use this error instead of err. 111 00:05:35,620 --> 00:05:38,963 So here, and here, and here. 112 00:05:41,720 --> 00:05:42,770 Alright? 113 00:05:42,770 --> 00:05:44,890 And so, let's now go ahead 114 00:05:44,890 --> 00:05:47,223 and actually create this function here. 115 00:05:49,580 --> 00:05:52,883 So let's put that up here right in the beginning. 116 00:05:56,247 --> 00:05:57,413 Alright. 117 00:05:58,270 --> 00:06:00,680 Try to remember that this receives an error, 118 00:06:00,680 --> 00:06:04,210 and now I'm going back to just calling it err like this, 119 00:06:04,210 --> 00:06:07,320 because again that's kind of the standard in Express. 120 00:06:07,320 --> 00:06:09,020 And to start, let's take a look again 121 00:06:09,020 --> 00:06:12,910 at the error object here, okay? 122 00:06:12,910 --> 00:06:17,910 So here, we have the path, and we have also the value, okay? 123 00:06:18,290 --> 00:06:21,280 So the path here is basically the name of the field 124 00:06:21,280 --> 00:06:25,000 for which the input data is in the wrong format, okay? 125 00:06:25,000 --> 00:06:27,860 And that value here is then this one, 126 00:06:27,860 --> 00:06:31,050 which is, of course, the one that we past did, alright? 127 00:06:31,050 --> 00:06:34,200 So, this might not only happen for the ID, 128 00:06:34,200 --> 00:06:36,450 but really, for any field that we query for 129 00:06:36,450 --> 00:06:39,370 with a value in the wrong format, alright? 130 00:06:39,370 --> 00:06:41,270 And so, let's now basically create a string 131 00:06:41,270 --> 00:06:43,330 that says that we have an invalid ID 132 00:06:43,330 --> 00:06:48,330 with the value of this one in this case, alright? 133 00:06:48,360 --> 00:06:53,360 So, it's path and value, okay? 134 00:06:53,530 --> 00:06:55,873 So, let's create a message here, 135 00:06:59,780 --> 00:07:01,770 and say Invalid err.path 136 00:07:08,328 --> 00:07:09,411 is err.value. 137 00:07:13,870 --> 00:07:15,250 Okay? 138 00:07:15,250 --> 00:07:17,813 And so now, we simply return our own AppError. 139 00:07:18,990 --> 00:07:20,227 Okay? 140 00:07:20,227 --> 00:07:24,270 So just like I mentioned a couple of times by now, okay? 141 00:07:24,270 --> 00:07:27,740 So AppError, and I actually have to include it here, 142 00:07:27,740 --> 00:07:30,933 or to require, because I didn't do it yet. 143 00:07:31,940 --> 00:07:35,633 So const AppError is equal to require, 144 00:07:39,150 --> 00:07:42,620 and move one level up, then into the utilities folder, 145 00:07:42,620 --> 00:07:45,213 and then the appError. 146 00:07:46,350 --> 00:07:47,183 Here it is. 147 00:07:48,150 --> 00:07:52,570 And so now, into or AppError, we pass in our message, 148 00:07:52,570 --> 00:07:56,860 and the 400 status code, which stands for Bad Request. 149 00:07:56,860 --> 00:07:59,040 Okay, and so just like this, 150 00:07:59,040 --> 00:08:00,940 we transform the weird error 151 00:08:00,940 --> 00:08:02,640 that we were getting from Mongoose 152 00:08:02,640 --> 00:08:04,110 into an operational error 153 00:08:04,110 --> 00:08:06,354 with a nice friendly message that 154 00:08:06,354 --> 00:08:07,187 (chuckles) 155 00:08:07,187 --> 00:08:09,343 an actual human can read, alright? 156 00:08:10,684 --> 00:08:13,270 Okay, one last thing that we need to change here 157 00:08:13,270 --> 00:08:18,150 is to also set this one here to error, okay? 158 00:08:18,150 --> 00:08:21,750 And so, right now, if our error is CastError, 159 00:08:21,750 --> 00:08:24,770 well, we will then pass the error into this function 160 00:08:24,770 --> 00:08:27,790 which will return our AppError, so this one, 161 00:08:27,790 --> 00:08:31,430 and that is the one that will then be sent to the client 162 00:08:31,430 --> 00:08:34,180 using our sendErrorProd, okay? 163 00:08:34,180 --> 00:08:36,123 And so, let's now actually try that. 164 00:08:37,080 --> 00:08:39,060 So here, in our package.json, 165 00:08:39,060 --> 00:08:43,627 we have this start:prod script, and so let's try that. 166 00:08:43,627 --> 00:08:48,627 So, npm run start:prod, and I can actually auto complete 167 00:08:50,250 --> 00:08:54,580 these npm script names using tab here in the terminal, okay? 168 00:08:54,580 --> 00:08:56,420 And so, this will start a process 169 00:08:56,420 --> 00:08:59,640 in production mode, basically, okay? 170 00:08:59,640 --> 00:09:01,060 And so, let's now try this again. 171 00:09:01,060 --> 00:09:02,580 So, if you're now doing this request, 172 00:09:02,580 --> 00:09:04,350 we should get back the error message 173 00:09:04,350 --> 00:09:07,500 that we just created, 'cause right now, we're in production. 174 00:09:07,500 --> 00:09:10,060 And indeed, here it is. 175 00:09:10,060 --> 00:09:12,530 So we have invalid, and then field name, 176 00:09:12,530 --> 00:09:15,010 or actually the path name, and then the value 177 00:09:15,010 --> 00:09:15,843 that we put in. 178 00:09:17,130 --> 00:09:19,194 So if we try something different, then of course, 179 00:09:19,194 --> 00:09:21,730 we get this, and of course, 180 00:09:21,730 --> 00:09:25,450 also our 400 Bad Request code. 181 00:09:25,450 --> 00:09:26,650 Okay, great. 182 00:09:26,650 --> 00:09:28,533 So, this one is now handled. 183 00:09:28,533 --> 00:09:32,210 In the next lecture, we will then take care of the next one, 184 00:09:32,210 --> 00:09:35,440 which is for duplicate field names, alright? 185 00:09:35,440 --> 00:09:36,890 So, see you then in a second.