Global error handling in angular using interceptor | Free Angular Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
So in our previous video we have integrated our login and register component with WebAPI. We have seen how to call WebAPI methods and how to trap errors at the client side. We understood the basic concept and it is working quite well. But definitely this is not the best approach. If you have only one or two components, then it is fine to trap errors like this in components. But if you have 1000s of components, this is really bad advice to follow this approach. Because we need to repeat this code in all the components. Although we can write this error trapping logic in our service as well. But we may have 100s of different services as well in bigger applications. Then also we need to repeat this error trapping logic in all of our services. This is a very serious anti pattern and we should never repeat our code. Also if something needs to change with the way we handle errors, for example suppose later we decide to log all the HTTP errors in a database, we have to update each and every component or service, if we follow this approach. Angular provider http interceptor to intercept all http requests and responses to transform or handle the errors, before passing further in the chain. We can use http interceptor to create a global error handling middleware just like we had created in our WebAPI, to solve this problem. So in this video we are going to add an interceptor in our angular application and also we will make some changes in our WebAPI as well, to return errors in a more consistent way throughout the different controllers. So without further ado let’s implement an interceptor in our angular app to handle the error globally next. So we will add an interceptor as service, we can also use angular CLI to generate an interceptor using ng generate interceptor and provide the name of interceptor. But I am adding this first interceptor manually, so that you can understand the concept deeply. Let’s export the class as we need to use this in other modules, name it HttpErrorInterceptorService and this class must implement HttpInterceptor. And any class that is implementing HttpInterceptor must have a method named intercept, that should have two arguments. First one should be the HttpRequest that we can intercept here and transform it as per our requirement before sending it further in the chain. Let’s name it request. And the type of this argument is HttpRequest and it is a generic type. We need to pass the type of data here that should be carried by this request. But we want to make it generic and we do not know what kind of data a request will get here, so I am going to use ‘any; here or we can also use ‘unknown’ as well here. And the 2nd argument of this method typically is a function or better we can say it is an object of type HttpHandler, that provides us a handle to pass the transformed request to the next interceptor in the chain. We typically return an observable of event stream here in this method, using next.handle and pass the request here. This is very important, if you do not call this next handle, you will break your application, as your request will not pass further in the flow of application. We can perform some operations on this request using some rxjs operators on this request, before sending the same to the next interceptor. We will look at that shortly. But before that, let’s just write something before this return statement in the console. Let’s say “HTTP Request started” So this is the typical setup of an interceptor. And finally in order to tell about our interceptor, as usual we will have to go to the appmodule. Scroll down to the providers array. And here we need to add a javascript object. We need to provide 3 properties here, the first one is “provide” and here we need to use HTTP_INTERCEPTORS, all in capital letters. This is the token name that angular will look in all the classes and will consider those classes as Interceptor and run those classes in the chain. And the second property is useClass. And here we need to tell the name of our interceptor class. And the 3rd property is multi. And it must be set to true in the case of HTTP_INTERCEPTORS because it is a multiprovider token and if we will not set this property true, it will not work. Required modules automatically be imported on the top, but in case if these are not added automatically by VS code. Then you will have to import these classes manually at the top like this from angular/common/http. So our interceptor is now ready, let’s run our application and see what we get in the console. So if you refresh this page, we are already calling http get method to load this home page data from JSON file using HTTPGet method. So our interceptor should be called. Yup, it's called as we get this line here “HTTP Request Started” that we put in our interceptor. And if we try to login, let’s just use some invalid username and password. Yup, this time as well our interceptor is called. So our setup is working fine. Next we will see how to move all of our error handling logic in the interceptor and remove it from the component. We can use the pipe operator on this observable, that will take this observable as input and inside this pipe we can use the different RxJS functions. And to catch the error we will use, catchError, this method has one argument to get error. And type of this error is HttpErrorResponse. And in this method we can log the error. Let’s copy all the code from our component and paste it here. Remove this line as it was wrongly imported. And this alertify is a service and in order to use it here, we will have to add the constructor in this class. And inject alertifyService here in constructor. And finally it is important to return an error from this function, let’s throwError and return error.error. You can see all of these modules are automatically getting imported here at the top of this class. Just to remind you, sometimes it does not work in vscode and you have to manually import a few modules here. Also you need to add this injectable decorator at the top of this class and it should be provided in root. Otherwise this alertify notification will not work. So now we can remove this error handling code from our component class. Let’s try to login, first provide some invalid user name, so that we can see if our interceptor is catching our error or not. Perfect, we are getting this alert from our interceptor. And if we provide the correct user ID and password. Yup we are successfully logged in, that means our interceptor is correctly passing requests further in the chain. Now we can remove this error handling code from the register component as well, because our interceptor will work globally for all http requests. We do not need to put this error handling logic now in any component or service. Let’s try to add a user that already exists, and it should throw an error from the interceptor. Yup, we are getting an error notification from the interceptor. So happy path or we can say positive test cases are working fine. Let’s test it for few negative test cases as well. Let’s see what will happen if our API server is down. Trying to login, doesn't matter if we use invalid or valid users, as our API server is down at the moment. Definitely our interceptor has catched this error, but we did get any clue in this notification of what wrong has happened here. And if we look at the console, you can see this time we get this JSON object in error, it is not directly exposing the error as we were getting previously. And if we look at the other nodes, you can see we get status as zero here. So whenever we do not get any response from API or API server is down. We always get zero here in the status node. So we can use this status code in our interceptor to display “Unknown error” or something else you would like to display to the user on the base of this status code. Let’s create a separate method to set Error, instead of directly putting if else conditions here in catch error block. Accept the error response here as an argument, that we will pass from the catch error block. This method will return a string type. Let’s define errorMessage and set the default value as “Unknown error occurred”. There are two kinds of errors that usually occur in angular apps. One is client side errors, that we usually throw from the frontend. We can identify client side errors by checking the instance type using instanceof type, and client side error instance type is ErrorEvent. So we can handle “client side error” in this block. And set errorMessage here. We get the error message in error.message node for client side errors. All other types of errors are server side errors. Set the error message - error.error. And return this errorMessage here. At present we are throwing all known errors in this format error.error. But as you have seen if our server is down. This is a kind of unknown error and we got a json object in that node, you have seen it results in throwing a blank notification to the user. And we know if the server is up, error.status will not be zero. So if error.status is not zero, we will set the error message using error.error. And as we already have set the default value here and if all of these conditions are failed, this method will return the default value as “Unknown error occurred” Let’s use this method here in the catch block. Define a constant, name it errorMessage and set its value using this.seterror and pass error in the argument. And use the constant here in both the places. So if now we will try to login, perfect, we are getting this unknown error notification. So it’s working fine for both the test cases like for the “handled” error that is returned by our API and the 2nd test case is also handled to return an unknown error if the server is down. The handled error that is being returned by our controller is defined here. So when the user was invalid we are throwing this error in error response. Let’s think what will happen, if in case our API is running, but our database server is down. That is also possible in real world scenarios. Let me stop the SQL Server instance so that we can replicate this issue in our WebAPI. We are not handling this error in our controller. And our exception middleware should catch this error. And you can see, we are returning all unknown error responses using this class, we have some properties here to set error code, error message and error details. And if the environment is development, we are returning this error trace as well. But we are not returning the error trace in the production environment. And this is totally a different kind of json object, we are returning from here in case of unhandled error. So our database server is down, let’s see what will happen if we try to login now. Again we got blank notification this time. And the reason is we got status code 500, that is not zero this time, so our interceptor did not consider this as unknown error. And error node contains a JSON object, that contains 3 different properties. But our interceptor is expecting a string in this error node. So to fetch this error in our interceptor, we will have to use error.errorMesssage here. But we are still getting blank errors. Let me check the node, maybe I have made some spelling mistake. Yup got it, we are returning these 3 properties in Pascal Notation, the first character is capital. But if you look at the other nodes, we are getting node names in camel case notation. So either we have to use here as well as pascal notation. And if I change the first letter capital here, we should correctly fetch the error. But I do not want to go with this approach and would like to keep the same standard for all error nodes. Let’s correct this behaviour at API level instead of renaming it to the pascal notation. So go to the API Error class and here we are serializing this object. By default dotnet use pascal notation for json serialization. But we can also set the camel case using the JsonSerializer Options and set propertyNamingPolicy to JsonNamingPolicy.CamelCase. Now we can pass this option as the 2nd argument of this serialize method to tell that all the properties should be serialized in CamelCase. Save it and Let’s try to login one more time. Yup we get this error detail now that is thrown by our API middleware. We are getting so much details in this error because we are running our API in a development environment. But if we will run it in the production environment, we will get only “Internal Server Error” here in the notification. You can see, now we are getting all properties here in camel case notation. So it's working fine for unhandled error now, but it will start to fail for the handled error that we already have tested, because in our controller we are not using this API Error class to return an error response. So we will use the object of the same class here as well for the handled error in all of our controllers. We should always be consistent in returning error responses so that our API client should not have to put so many if else cases to correctly display the error at their end. So let’s define a variable of type ApiError. It seems we do not have a constructor in this class that accepts null arguments, that is why I am getting this error here. Yes, we do not have that in place. Let’s add one more constructor with a blank argument here, so that we can instantiate the object without passing any argument. Save it. And now the error has gone. We can now set the properties of this object here. Set error code = it should be the code of error we are going to return in the response. We can use unauthorized.status code here to get the correct error code for unauthorized error. And set the apierror.ErrorMessage, Just copy this message from here. And also we can set the 3rd optional argument here to set the errordetails, where we can provide some details of this error. Let’s tell the user that “This error appear when provided user id or password does not exists”. And finally return this apiError object here in response. Let’s run the database server and test if we are correctly getting this handled error or not. And if I try to login using invalid user id. Yup, we are getting the correct error. And in the console we are getting JSON objects in the error node with all of these 3 properties that we are setting from our controller. So we have tested all 3 test cases, one when API server is down and another when database server is down and the 3rd one when handled error is thrown by our API and all 3 are working fine. And also we need to update this register method as well to return error using the object of type APIError. So this time I have not set errorDetails. Let’s test it by trying to create a user that already exists in the database. Yup we are getting errors properly on the component as well. And in Console, if we examine this error node, we get null in errorDetails property as we are not setting anything for this property in our controller. So we have successfully implemented global error handling using interceptor in this video and also updated our API to return consistent error response in different methods. We were supposed to fix this issue as well by putting a validation check to return error in case users try to pass a blank user name or password in this video, but video has become little lengthy. And, so I would like you to take it as an exercise. As a hint we need to put a check here in the register method. We need to check if the provided user id or password is blank, then we will have to return this badrequest. And we should return the error response using the API error class. You can use string.isnullorEmpty function on the user id and password for this check. And if that is true, you need to return the bad request. If you are not able to do that, no worry I will explain the same in our next video. And we will also see how to add an extension method to incorporate null checks more efficiently, so that we can use that extension throughout the application. Also we will see how to implement retry logic in our interceptor, so that http requests should be able to retry automatically in case some connectivity issue happens during http calls. And also please tell me some more scenarios that we can implement in our interceptor, feel free to ask if you have any questions. Please like this video, if you really learned something new in this video. And… see you in the next video, stay tuned, bye bye.
Info
Channel: Study Mash
Views: 17,430
Rating: undefined out of 5
Keywords: global error handling in angular 9, angular service error handling, angular tutorial for beginners step by step, angular interceptor error handling, angular tutorial, angular interceptor catch error, free programming tutorials, angular http interceptor, angular interceptor interview questions, http error handling in angular, studymash, global error handling in angular 10, angular tutorial for beginners, angular interceptor example, angular interceptor tutorial
Id: dp08jPXg4g0
Channel Id: undefined
Length: 20min 23sec (1223 seconds)
Published: Sun Apr 04 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.