
Join the Conversation!
Subscribing gives you access to the comments so you can share your ideas, ask questions, and connect with others.
How do I remove the blur effect from my CSS?
I removed but the blur is still there. Any ideas?
filter: blur(5px);
Does work for removing blur from modals?
backdrop-filter: none;
Subscribing gives you access to the comments so you can share your ideas, ask questions, and connect with others.
Complete source code available till this point of lesson is available at
By logging in, you'll unlock full access to this and other free tutorials on JSM Pro.
Why? Logging in lets us personalize your learning experience, track your progress, and keep you in the loop with new workshops, coding tips, and platform updates.
You'll also be the first to know about upcoming launches, events, and exclusive discounts.
No spam—just helpful content to level up your skills.
If that sounds fair, go ahead and log in to continue →
Enter your name and email to get instant access
##Looks like we found a thief monkey By the way, I liked the trick how you reached till here. You have a good sense of humor. You will improve a lot if you join our course with this passion.
var
(function-scoped, outdated)let
(block-scoped, modern and recommended)const
(block-scoped, cannot be reassigned)_
, or $
let let = 5;
is invalid)myVar
and myvar
are different)string
, number
, boolean
, null
, undefined
, bigint
, symbol
Objects
, Arrays
, Functions
Subscribing gives you access to a brief, insightful summary of each lecture to stay on track.
00:00:02 When it comes to implementing error handling within our application, we'll have to do it both for our server actions as well as for our API routes.
00:00:11 So whatever system we create has to work for both.
00:00:15 So first things first, let's compile a list of potential error types and assign relevant information for each one to avoid repetition in the future.
00:00:25 We can do that by heading over to lib and creating a new file called http-errors.ts.
00:00:33 Inside of here, we can export a new const, but this time it won't be a const.
00:00:39 I'll actually be using a class keyword.
00:00:42 So why will we use classes here?
00:00:44 Well, because they're going to help us keep our error types organized.
00:00:49 We're going to define something known as a base class, which we can then extend on other classes.
00:00:55 Let me show you how that works.
00:00:57 class request error extends the error class.
00:01:02 And this is one of the rare occasions where I would still use classes in JavaScript for error handling.
00:01:08 Keep in mind this has nothing to do with React or Next.js.
00:01:12 This is just a regular JavaScript class, allowing us to extend different errors.
00:01:17 So first we have the request error, which extends the error, which is the default error.
00:01:23 But then we can create some more specific errors like class validation error which will then extend the request error because a validation error will be
00:01:32 of a type request and then that will also extend the base error.
00:01:36 We can also have some other ones like class not found error which will extend the request error.
00:01:42 We can have a forbidden error and finally the unauthorized.
00:01:47 If we had used functions instead, we would have to create separate functions for each error type, which could lead to repeated code,
00:01:53 and it could make it harder to handle related errors together.
00:01:57 In this case, and in bigger applications, classes are just super simple to use when it comes to error handling.
00:02:04 So let's start with defining the base request error.
00:02:07 We can say that each request error will take in a status code of a type number, as well as the errors object.
00:02:17 So that's going to be of a type record where we get a string and an array of strings for the errors.
00:02:24 Next, we can define a constructor, meaning what are we accepting into this class when creating an instance out of it?
00:02:31 We need a status code of a type number.
00:02:34 We need a message of a type string.
00:02:37 And finally, we need a list of errors, which is going to be that record type that we created above.
00:02:43 And once we have the constructor, we can just pass the message into the super right here.
00:02:49 Super simply calls the parent class and passes the error message.
00:02:55 So in this case, we're passing the message into the parent error class.
00:02:59 This initializes the base error functionality and sets the message property on the error instance.
00:03:05 And finally, we can also set all of the other things like the status code equal to the status code.
00:03:11 This is that error is equal to errors.
00:03:13 And we can also add a name.
00:03:15 So this, that name is going to be equal to request error.
00:03:19 So this is going to be the default base request error, but later on we can change that name to be a bit more specific, whether it's a validation error,
00:03:27 not found error or anything else.
00:03:31 And that's it.
00:03:32 This is our request error.
00:03:34 Now we can use it and based on it, we can extend the validation error.
00:03:39 So let's do that.
00:03:41 In the validation error, we're going to have a constructor.
00:03:46 of field errors, which is going to be equal to that same record where we get a string and then an array of strings and within the constructor.
00:03:56 So once we create an instance out of this request, we can set the message.
00:04:02 to be equal to validation error dot format message to which we pass the field errors.
00:04:09 And how do we have access to this format message on the validation error?
00:04:13 Well, we can declare it by saying static format field errors to which we pass the errors object.
00:04:23 And then specify that it is a type of a record that has a string and an array of strings that we can get right into it.
00:04:31 And we can also specify that it will return a string that's going to look something like this.
00:04:36 And now it should not complain right here.
00:04:39 It will not complain once we actually call a super because this class has to call the class above it.
00:04:44 So we can say super.
00:04:46 pass the message of 400, which is the status code, pass the message into it, and then pass the other field errors if there are any.
00:04:54 And we can also set the this.name to validation error and this.errors to be equal to field errors.
00:05:02 Great.
00:05:02 And I misspelled string right here.
00:05:05 With that, we're looking good.
00:05:07 I know this can be very overwhelming and very weird, let me put it that way, because we're used to the JavaScript as the functional language,
00:05:15 not class-based language.
00:05:17 But it can actually do both, and from time to time I like to switch.
00:05:21 Now I do have a background in a Java programming language back from the university day, which definitely helps with understanding of the classes.
00:05:29 So if you don't have that background, or if this is your first time meeting classes, which could be for many of you, that's totally normal.
00:05:38 And I don't expect you to understand every single one of the bits that we write here.
00:05:43 You can copy the code, you can take it to chat GPT, you can Google how the constructor works, how the super works.
00:05:49 But I don't really expect you to do that.
00:05:51 Once I write the entire HTTP errors file, I'll go ahead and explain it once again.
00:05:56 But for now, I just want you to know that we are doing some error handling here.
00:05:59 We decided to use classes because they allow us to extend other classes, making our error handling more manageable.
00:06:07 And that's more or less it.
00:06:09 I can also quickly ask ChatGPT to generate a functional version of this entire file once we're done with it, just so you can compare the differences.
00:06:16 And if you'd like to, you can maybe even keep the functional one.
00:06:20 But with that said, let's continue creating the form field errors function.
00:06:25 Instead of here, we want to get access to the error message that we pass into it by saying const formatted messages is equal to object.entries of errors
00:06:38 that we pass into it.
00:06:40 And once we get it, we can map over it.
00:06:43 And then we can destructure the field and the messages from each one of these errors.
00:06:51 And for each one, we can declare a field name, which is equal to field dot car at zero dot to uppercase.
00:07:02 And then plus field dot slice one.
00:07:04 So here we're basically uppercasing the field name.
00:07:07 And then if messages zero is triple equal to required, then we will return field name is required.
00:07:15 Else we will return messages dot join and we'll append the.
00:07:23 And to it.
00:07:25 I'll explain what this does later, but basically this formatFieldErrors method is a static function that means that it can be called on a class itself
00:07:34 without needing its own instance.
00:07:36 As you can see right here, we're calling it on the class and it takes a record of field errors as input and returns a formatted string.
00:07:44 It's going to say something like first name field is required.
00:07:47 As simple as that.
00:07:49 Finally, we can exit out of this dot map.
00:07:53 And return the formatted message and join it by a comma.
00:07:57 Now, why are we doing this?
00:07:59 Because it can contain many different missing fields that are required.
00:08:02 So this way we're just appending them one after another and setting that as a single message that we return.
00:08:08 Looks like in this case, we have format message.
00:08:11 But this should have been format field errors.
00:08:13 So if we call it properly, it no longer complains.
00:08:17 Now I can go ahead and export both of these classes.
00:08:20 So expert class request errors, as well as expert class validation error.
00:08:26 So we can use them later on within our code.
00:08:29 And now let's quickly do the other three, starting with not found error.
00:08:34 Here, I can create a constructor that accepts a resource of a type string.
00:08:39 And I'm going to simply call the parent method of request error with a status code of 404 and say resource not found and set the name to not found error.
00:08:52 I'm going to do a similar thing with a forbidden one where I'll call the constructor to which I will accept or pass a message of a type string by default
00:09:03 being unauthorized or in this case forbidden.
00:09:06 And then I'm going to call a super with a 403 for forbidden and pass in the error message and set this that name to forbidden error.
00:09:19 And I can repeat the same thing for unauthorized.
00:09:22 We're going to call a constructor with a message of unauthorized by default.
00:09:26 That's going to be 401 with the message and the name will be unauthorized there.
00:09:31 And we can immediately export.
00:09:35 all of these three error classes so we can use them later on within our code.
00:09:39 And remember why we created this file in the first place?
00:09:42 That is to list all potential errors and assign relevant information to them so we can more easily call them later on within our error handling system.
00:09:51 Now with that out of the way, we can actually create an error handler in lib folder, handlers, and then within a file called error.ts.
00:10:03 Later on, we'll have more handlers like one for fetching from API requests.
00:10:07 So we'll create a separate folder for it, but for now we can implement this error handler.
00:10:12 Let's start by defining a new type.
00:10:15 export type response type is equal to either a string of API or server because something can be an API call and something can be a server action.
00:10:28 So given those two different things, we'll have to handle errors differently.
00:10:33 Next, let's define a function format response, which is going to take in a couple of parameters.
00:10:39 The first one being response type of a type response type.
00:10:44 Next, we're going to have a status, which is going to be a number status code.
00:10:50 We're going to have a message, which is going to be of a type string.
00:10:54 And finally, we're going to have a list of errors, which as you already know, will be of a type record.
00:11:02 of a string and then string array, or potentially it can also be undefined if we're not getting any additional info through the error.
00:11:11 Now we can open up a function block.
00:11:15 And form how a response should look like by saying const response content is equal to an object or the success is obviously false because we have encountered
00:11:29 an error and we need to form the error object to which we're going to pass the message as well as details is going to be equal to errors.
00:11:40 Finally, we can return and check if the response type is triple equal to API.
00:11:48 In that case, we're going to return a next response.
00:11:52 coming from nextServer.json to which we're going to pass the response content and the status.
00:11:59 But if it's a server action, we don't have to wrap it in a next response.
00:12:03 We simply return an object with a status and we spread the response content.
00:12:10 I hope this is making just a bit of sense.
00:12:12 You'll see it later on once we use it in action.
00:12:15 Now that we have this format response, we can create the main function, which is going to be the handle error function.
00:12:21 So let's say const handle error, which is going to accept in the error of a type unknown because at the time we don't yet know what it is.
00:12:31 And the response type of a response type by default equal to server action, because we're going to have more of those.
00:12:39 And at the bottom, we can export default handle error.
00:12:44 So now let's implement that error handling function.
00:12:47 First, I want to check if error is an instance of request error.
00:12:56 coming from HTTP errors.
00:12:58 That's the class that we created.
00:13:00 And if it is, that's going to be amazing because then we already have a lot of information.
00:13:04 We know that it'll have some kind of a status code, a list of errors, and maybe even a message.
00:13:10 So we are ready to log something out.
00:13:13 Right here, say return, format response, and pass it whatever it needs.
00:13:19 It needs a response type, error.status, error.message and error.errors.
00:13:26 And I believe that we called it a status code right here on the other side.
00:13:30 So that's going to be the correct way to do it.
00:13:33 We can also check if it's some kind of an other error, like if this error is an instance of zod error.
00:13:44 Then we know that it is a validation error, and this Zod error of course has to be imported from Zod.
00:13:50 And if it is, we're going to form the validation error by saying const validation error is equal to new validation error.
00:13:59 So we're creating a new instance of our class to which we're going to pass the error.flatten.
00:14:07 Why?
00:14:07 Because it's possible that this errors array contains multiple arrays of errors, believe it or not.
00:14:13 So we want to flatten it into a single array.
00:14:16 And the array that flatten does exactly that.
00:14:18 If you have an array of arrays, it simply turns it into a single array.
00:14:22 And then we can call the dot field errors on it.
00:14:27 And we can say that this is of a type record as string and then string array.
00:14:32 Once we have the validation errors, we can simply return the format response with everything else that it needs.
00:14:39 We can also have one more if and say if error is an instance of regular error.
00:14:46 In that case, we don't have a lot of info, so we can simply return format response with a response type 500 as the general server error issue and the error
00:14:58 message if we have it.
00:15:00 And by default, we can return a format response 500 of unexpected error has occurred.
00:15:08 So believe it or not, this is it.
00:15:09 This is a part of error handling implemented.
00:15:13 So how do we actually test this?
00:15:15 Well, let's head over to our root page.tsx and scroll a bit up.
00:15:22 Right here where we have some dummy questions, create a new function, call it const test is equal to an async function like this,
00:15:31 and open up a try and catch block.
00:15:35 In the catch, return the handle error function call to which we simply pass the error.
00:15:41 Believe it or not, this is it.
00:15:43 You call the handle error and you pass it.
00:15:45 No more console logging, no more nothing.
00:15:47 You just call the function that we created that we worked so hard on, and then you simply pass in the error.
00:15:53 And that error then contains the status code, the message, the errors, and you can more properly give info on what went wrong,
00:16:00 both the user as well as to the developer.
00:16:04 So now here, we can try to throw some errors.
00:16:07 Let's say throw new error and simply pass test error into it.
00:16:12 Now right here, back in our function at the top, we can say const result is equal to await test.
00:16:24 And then you can console log the result to see if something comes back.
00:16:28 That's what we want to see, right?
00:16:29 And let's say that this is a piece of code that will break our application, the test function in this case, which will throw a new error.
00:16:35 Now, if you go back to your homepage, reload, and open up the terminal, let's see what do we have.
00:16:42 We get a status 500 with a success of false, the error with a message of test errors, and details of undefined.
00:16:51 Obviously, something didn't go right, but unfortunately, we don't have a lot of info on exactly what went wrong.
00:16:57 This is the generic error.
00:16:59 But what if we try to throw a not found error coming from libutils?
00:17:07 If I save it, reload, you can see that we have a status of 404, which means not found.
00:17:17 And we also have a test error, not found right here, because that's the name of the page we're trying to get.
00:17:22 In this case, it would make sense to say home.
00:17:24 So it could say home, not found.
00:17:27 Finally, what if we have a validation error?
00:17:30 So let me say throw new validation error.
00:17:35 And we're going to pass in an object that's going to contain a title equal to required, which means that the title is required and tags,
00:17:46 which is going to say something like an array of JavaScript.
00:17:51 is not a valid tag.
00:17:54 This is a typical error message that you might see.
00:17:57 So with the validation, we typically have more errors.
00:18:00 So now if I save it, check this out, we have a status of 400, success, false, and then the error message saying title is required and JavaScript is not
00:18:09 a valid string.
00:18:10 and then we have more details for each one of these fields on its own.
00:18:14 This is great.
00:18:15 And it means that our error handling is working, and the only thing we have to do is simply call this.
00:18:22 Not this entire function, just this.
00:18:25 Whenever you're doing what you usually are, you simply wrap it in a try and catch block, you call the handleError function,
00:18:31 and you pass in the error.
00:18:33 That is it.
00:18:35 Now I'll remove it from the home page so it works again, and I'll remove this part from the home page as well.
00:18:41 Now before I finish this lesson up, I noticed I have one red squiggly line right here, so let's go ahead and fix it.
00:18:47 It says property credit ad is missing in type.
00:18:51 If we go into the question card and go to the question type, it looks like I misspelled create it.
00:18:58 So if I fix this, I believe we should be good.
00:19:01 I'll just make sure to reload all of these pages, fix it, and the error is gone.
00:19:07 Great.
00:19:08 So now I'll actually commit this and push it by saying implement error handling, commit and push.
00:19:17 And in the next lesson, I'll teach you how to implement logging.