1 00:00:01,100 --> 00:00:02,750 In this video, let's now create 2 00:00:02,750 --> 00:00:05,470 a better and more useful error class, 3 00:00:05,470 --> 00:00:07,373 and also do some refactoring. 4 00:00:09,210 --> 00:00:11,870 And starting with that error class, 5 00:00:11,870 --> 00:00:15,053 let's create a new file in our Utilities folder. 6 00:00:15,950 --> 00:00:18,990 So, new file, and I'm going to call it AppError 7 00:00:20,980 --> 00:00:25,820 because that's going to be the name of the class, all right? 8 00:00:25,820 --> 00:00:30,820 So, class AppError, and we actually want all of our 9 00:00:30,867 --> 00:00:34,780 AppError objects to then inherit from the built-in error, 10 00:00:34,780 --> 00:00:39,260 and so let's actually extend the built-in error class. 11 00:00:39,260 --> 00:00:43,720 So, we used extends Error, okay? 12 00:00:43,720 --> 00:00:46,870 So, we did that before somewhere in this course, 13 00:00:46,870 --> 00:00:50,950 and again this is just ES6 classes, all right? 14 00:00:50,950 --> 00:00:52,920 In this case, class inheritance, 15 00:00:52,920 --> 00:00:56,790 where one class inherits from the other, okay? 16 00:00:56,790 --> 00:00:59,300 Then, as always, our constructor, 17 00:00:59,300 --> 00:01:01,800 and what we're going to pass into a new object 18 00:01:01,800 --> 00:01:04,490 created from the AppError class is going to be 19 00:01:04,490 --> 00:01:08,660 the message and the statusCode, 20 00:01:08,660 --> 00:01:09,853 so just these two. 21 00:01:11,330 --> 00:01:15,130 Okay, so, remember the constructor method is called 22 00:01:15,130 --> 00:01:19,210 each time that we create a new object out of this class. 23 00:01:19,210 --> 00:01:22,116 Now, as usual, when we extend a parent class, 24 00:01:22,116 --> 00:01:25,760 we call super in order to call 25 00:01:25,760 --> 00:01:28,203 the parent constructor, all right, 26 00:01:30,100 --> 00:01:33,580 and we do that with message because the message is actually 27 00:01:33,580 --> 00:01:37,160 the only parameter that the built-in error accepts. 28 00:01:37,160 --> 00:01:40,990 Okay, so this is basically you're, like, calling error, 29 00:01:40,990 --> 00:01:44,305 all right, and then this is here is the usual stuff, 30 00:01:44,305 --> 00:01:46,160 we set the statusCode 31 00:01:48,300 --> 00:01:53,030 to statusCode, all right, 32 00:01:53,030 --> 00:01:56,463 and now we also want to set the status itself. 33 00:01:58,200 --> 00:02:01,670 So, remember the status can either be fail or error, 34 00:02:01,670 --> 00:02:03,920 and we could pass that into the object, 35 00:02:03,920 --> 00:02:05,700 but it's also not really necessary, 36 00:02:05,700 --> 00:02:08,530 because the status depends on the statusCode. 37 00:02:08,530 --> 00:02:10,880 So, when the statusCode is a 400, 38 00:02:10,880 --> 00:02:12,630 then the status will be fail, 39 00:02:12,630 --> 00:02:16,230 and if it's a 500, then it's going to be an error, right, 40 00:02:16,230 --> 00:02:18,336 and so that simply tests if the 41 00:02:18,336 --> 00:02:20,420 statusCode starts with a four. 42 00:02:20,420 --> 00:02:23,800 So, in JavaScript, there is a startsWith method 43 00:02:23,800 --> 00:02:25,540 that we can call on strings, 44 00:02:25,540 --> 00:02:28,100 and so I think that's the easiest way of doing this test, 45 00:02:28,100 --> 00:02:31,363 and so that's basically convert the statusCode to a string, 46 00:02:32,780 --> 00:02:35,610 and for that I'm simply using a template string with 47 00:02:35,610 --> 00:02:38,030 the code in there, so this, 48 00:02:38,030 --> 00:02:40,380 or actually we can just use statusCode. 49 00:02:41,781 --> 00:02:42,614 So, statusCode, and then startsWith, 50 00:02:47,001 --> 00:02:48,750 then here we also need a string, 51 00:02:48,750 --> 00:02:51,120 and so if the statusCode as a string 52 00:02:51,120 --> 00:02:54,330 starts with a four, well, then we have a fail. 53 00:02:54,330 --> 00:02:58,360 And so here, let's use the ternary, okay, 54 00:02:58,360 --> 00:03:02,120 and so it's fail when it starts with a four, 55 00:03:02,120 --> 00:03:06,890 and otherwise it's an error, okay? 56 00:03:06,890 --> 00:03:09,550 So, very simple, and this already saves us 57 00:03:09,550 --> 00:03:13,250 from manually have to pass in either fail or error. 58 00:03:13,250 --> 00:03:15,240 All right, now next up, 59 00:03:15,240 --> 00:03:17,120 all the errors that we will create 60 00:03:17,120 --> 00:03:20,300 using this class will all be operational errors. 61 00:03:20,300 --> 00:03:22,070 So, errors that we can predict 62 00:03:22,070 --> 00:03:24,130 will happen in some point in the future, 63 00:03:24,130 --> 00:03:26,010 like for example a user creating 64 00:03:26,010 --> 00:03:29,560 a tour without the required fields, right? 65 00:03:29,560 --> 00:03:32,380 So that is an operational error, okay, 66 00:03:32,380 --> 00:03:34,660 and so again, from now on, we will 67 00:03:34,660 --> 00:03:37,125 always use this AppError class here 68 00:03:37,125 --> 00:03:39,070 that we're creating right now 69 00:03:39,070 --> 00:03:42,230 in order to create all the errors in our application. 70 00:03:42,230 --> 00:03:44,730 And so these errors will be operational errors, 71 00:03:44,730 --> 00:03:46,250 and so what I'm gonna do now is 72 00:03:46,250 --> 00:03:49,663 to actually also create a .is operational property here. 73 00:03:50,980 --> 00:03:53,133 So this.is operational, 74 00:03:56,100 --> 00:03:57,380 and set it to true. 75 00:03:57,380 --> 00:03:59,240 So all of our errors will 76 00:03:59,240 --> 00:04:01,680 get this property set to true, 77 00:04:01,680 --> 00:04:03,420 and I'm doing that so that later 78 00:04:03,420 --> 00:04:05,890 we can then test for this property 79 00:04:05,890 --> 00:04:07,910 and only send error messages back 80 00:04:07,910 --> 00:04:10,360 to the client for these operational errors 81 00:04:10,360 --> 00:04:12,510 that we created using this class. 82 00:04:12,510 --> 00:04:14,550 And this is useful because some other 83 00:04:14,550 --> 00:04:17,210 crazy unexpected errors that might happen 84 00:04:17,210 --> 00:04:19,964 in our application, for example a programming error, 85 00:04:19,964 --> 00:04:22,360 or some bug in one of the packages 86 00:04:22,360 --> 00:04:24,550 that we require into our app, 87 00:04:24,550 --> 00:04:26,100 and these errors will then of course 88 00:04:26,100 --> 00:04:29,610 not have this .is operational property on them, 89 00:04:29,610 --> 00:04:31,610 all right, and it might sound 90 00:04:31,610 --> 00:04:33,370 a bit confusing at this point, 91 00:04:33,370 --> 00:04:35,220 but don't worry, it will make 92 00:04:35,220 --> 00:04:37,040 a lot of sense when we then 93 00:04:37,040 --> 00:04:39,860 implement that part that I just mentioned. 94 00:04:39,860 --> 00:04:43,740 So, testing for this .is operational property here. 95 00:04:43,740 --> 00:04:46,190 All right, and now just one last step 96 00:04:46,190 --> 00:04:50,270 is that we actually also need to capture the stack trace. 97 00:04:50,270 --> 00:04:53,090 Now, what do I mean by stack trace? 98 00:04:53,090 --> 00:04:55,430 And so, let me actually show that to you, 99 00:04:55,430 --> 00:04:58,380 so, show you what stack trace is, 100 00:04:58,380 --> 00:05:01,093 and so I will log it here to the console. 101 00:05:02,180 --> 00:05:05,053 Console.log and error.stackTrace, 102 00:05:06,390 --> 00:05:10,350 so each and every error gets this stack trace, 103 00:05:10,350 --> 00:05:13,370 and actually it's just stack, okay. 104 00:05:13,370 --> 00:05:15,820 So err.stack will basically 105 00:05:15,820 --> 00:05:17,743 show us where the error happened. 106 00:05:19,320 --> 00:05:20,743 So let me run this here now, 107 00:05:22,450 --> 00:05:24,303 and so let's take a look at this, 108 00:05:26,420 --> 00:05:28,000 and so it gives us here the error 109 00:05:28,000 --> 00:05:31,290 and then also where it happened, okay? 110 00:05:31,290 --> 00:05:33,040 So, in this case here, of course, 111 00:05:33,040 --> 00:05:36,390 add app.js at line 32. 112 00:05:36,390 --> 00:05:38,810 So, right here. 113 00:05:38,810 --> 00:05:40,470 So, that's where we created this error, 114 00:05:40,470 --> 00:05:42,200 and so it's now in our stack trace, 115 00:05:42,200 --> 00:05:44,972 and it also shows us the entire call stack here, 116 00:05:44,972 --> 00:05:49,972 which in the end the originated in this error, okay? 117 00:05:50,400 --> 00:05:52,440 So we kind of want to preserve that 118 00:05:52,440 --> 00:05:56,500 and also at the same time not add this method here, 119 00:05:56,500 --> 00:06:00,390 or this class, to that stack track, okay? 120 00:06:00,390 --> 00:06:02,350 And again, that sounds a bit confusing, 121 00:06:02,350 --> 00:06:03,980 I know, but in this case 122 00:06:03,980 --> 00:06:06,359 it's not really important, all that matters 123 00:06:06,359 --> 00:06:09,100 is that we just add this line of code here, 124 00:06:09,100 --> 00:06:11,873 which is Error.capturestackTrace, 125 00:06:13,670 --> 00:06:16,160 so exactly what you get here, 126 00:06:16,160 --> 00:06:19,490 and at first we need to specify the current object, 127 00:06:19,490 --> 00:06:23,530 which is this, and then the AppError class itself, 128 00:06:23,530 --> 00:06:26,113 which is gonna be this.constructor. 129 00:06:28,340 --> 00:06:31,220 Okay, and so this way when a new object 130 00:06:31,220 --> 00:06:34,361 is created, and a constructor function is called, 131 00:06:34,361 --> 00:06:36,388 then that function call is not gonna appear 132 00:06:36,388 --> 00:06:38,863 in the stack trace, and will not pollute it. 133 00:06:40,240 --> 00:06:41,073 All right, 134 00:06:42,250 --> 00:06:44,920 so let's put it down here, 135 00:06:44,920 --> 00:06:48,280 and yeah, so that's our AppError class, 136 00:06:48,280 --> 00:06:51,363 and so let's now actually export it from here. 137 00:06:52,450 --> 00:06:56,443 So, module.exports is of course the AppError. 138 00:06:57,340 --> 00:07:00,367 Great, just one question that you might have is 139 00:07:00,367 --> 00:07:04,720 'Why didn't I set this.message equal to message?' 140 00:07:04,720 --> 00:07:07,600 Well, that's just because right here I called 141 00:07:07,600 --> 00:07:10,253 the parent class, right, and the parent class 142 00:07:10,253 --> 00:07:13,380 is error, and whatever we pass into it 143 00:07:13,380 --> 00:07:15,350 is gonna be the message property. 144 00:07:15,350 --> 00:07:16,860 So just as I told you before. 145 00:07:16,860 --> 00:07:20,880 And so, basically, in here by doing this parent call 146 00:07:20,880 --> 00:07:22,890 we already set the message property 147 00:07:22,890 --> 00:07:24,463 to our incoming message. 148 00:07:25,970 --> 00:07:28,500 All right, give it a save, and now we can close it, 149 00:07:28,500 --> 00:07:29,653 we no longer need it, 150 00:07:30,770 --> 00:07:32,933 and here we're just gonna import it here. 151 00:07:34,621 --> 00:07:35,871 Const AppError, 152 00:07:38,980 --> 00:07:39,883 require, 153 00:07:41,560 --> 00:07:43,600 and then it's in utils, 154 00:07:43,600 --> 00:07:48,320 so Utilities, and appError, okay, 155 00:07:48,320 --> 00:07:51,423 and so now let's actually go ahead and use it. 156 00:07:53,280 --> 00:07:55,070 Comment out this piece of code, 157 00:07:55,070 --> 00:07:57,420 and actually delete the one that we had before, 158 00:07:58,860 --> 00:08:00,210 and that will now create the error 159 00:08:00,210 --> 00:08:02,650 right here inside of next. 160 00:08:02,650 --> 00:08:04,433 So, new AppError, 161 00:08:06,600 --> 00:08:07,783 and then the message, 162 00:08:09,430 --> 00:08:10,793 which is this one, 163 00:08:12,910 --> 00:08:14,023 and the status code. 164 00:08:15,620 --> 00:08:18,410 Right, and the fail, remember, will then automatically 165 00:08:18,410 --> 00:08:22,480 be figured out, and so let's delete all of this, 166 00:08:22,480 --> 00:08:23,723 give it a save here, 167 00:08:25,320 --> 00:08:29,630 and one more time, test out this wrong route, 168 00:08:29,630 --> 00:08:32,940 and indeed we still get our same error, 169 00:08:32,940 --> 00:08:37,530 and we also still get our exact same stack trace. 170 00:08:37,530 --> 00:08:40,280 Okay, and finally I actually also want 171 00:08:40,280 --> 00:08:43,550 to export this middleware here, okay? 172 00:08:43,550 --> 00:08:45,260 So basically, this handler 173 00:08:45,260 --> 00:08:47,150 because throughout the rest of the section, 174 00:08:47,150 --> 00:08:48,760 we're gonna build a couple of different 175 00:08:48,760 --> 00:08:51,700 functions for handling with different types of errors, 176 00:08:51,700 --> 00:08:53,280 and so I want all of these functions 177 00:08:53,280 --> 00:08:55,912 to be all in the same file, all right? 178 00:08:55,912 --> 00:08:58,920 And we can say that all of these functions 179 00:08:58,920 --> 00:09:02,310 that I just mentioned are handlers, okay, 180 00:09:02,310 --> 00:09:05,320 and so handlers, we also call them controllers 181 00:09:05,320 --> 00:09:08,240 in the context of the MVC architecture, 182 00:09:08,240 --> 00:09:10,130 and so let's now actually create 183 00:09:10,130 --> 00:09:13,253 an error controller file in our controller folder. 184 00:09:14,190 --> 00:09:18,280 Okay, and this might sound or look a bit weird 185 00:09:18,280 --> 00:09:21,330 because we actually do not have an error resource 186 00:09:22,200 --> 00:09:24,940 okay, and so probably some people are gonna disagree 187 00:09:24,940 --> 00:09:26,923 with me that this is the correct place, 188 00:09:28,540 --> 00:09:31,100 but I personally like to do it like this 189 00:09:31,100 --> 00:09:32,520 because at the end of the day, 190 00:09:32,520 --> 00:09:34,910 these functions, they kinda are like 191 00:09:34,910 --> 00:09:37,370 really for controlling our errors, all right, 192 00:09:37,370 --> 00:09:39,570 and so for me at least it makes sense 193 00:09:39,570 --> 00:09:43,140 to simply call this function here the error controller, 194 00:09:43,140 --> 00:09:46,500 and here I wanted to paste that middleware function, 195 00:09:46,500 --> 00:09:49,173 but I guess I didn't copy it, so let's do that again. 196 00:09:51,010 --> 00:09:53,540 All right, and so actually I'm gonna export 197 00:09:53,540 --> 00:09:56,240 this one here as the module.exports 198 00:09:56,240 --> 00:09:57,676 because the other handle functions 199 00:09:57,676 --> 00:09:59,606 that we're gonna create later on, 200 00:09:59,606 --> 00:10:02,440 I will not export them from here. 201 00:10:02,440 --> 00:10:05,453 So they are just kinda just gonna be helpers. 202 00:10:06,320 --> 00:10:11,320 So, module.exports equals this function, okay? 203 00:10:12,210 --> 00:10:15,420 Let's actually get rid of this console.log here, 204 00:10:15,420 --> 00:10:18,510 give it a save, and now back into our app 205 00:10:18,510 --> 00:10:21,080 we of course now need to plug in 206 00:10:21,080 --> 00:10:23,040 that middleware function here. 207 00:10:23,040 --> 00:10:25,660 So, let's again go ahead and import it 208 00:10:26,700 --> 00:10:28,710 and I can call it whatever I want, 209 00:10:28,710 --> 00:10:29,760 and so let me call it 210 00:10:30,802 --> 00:10:32,635 the globalErrorHandler 211 00:10:34,679 --> 00:10:36,853 with a capital H, 212 00:10:38,650 --> 00:10:39,840 and I'm gonna require 213 00:10:42,300 --> 00:10:45,033 controllers and errorController. 214 00:10:49,700 --> 00:10:52,660 Put it back here, and now for the final test 215 00:10:52,660 --> 00:10:54,343 after this refactoring. 216 00:10:55,810 --> 00:10:58,970 Let's see, and indeed 217 00:10:58,970 --> 00:11:03,040 one more time, everything works just fine, okay? 218 00:11:03,040 --> 00:11:06,490 So, perfect, that was the goal for this video, 219 00:11:06,490 --> 00:11:07,690 see you in the next one.