NestJS Interceptors

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this video you will learn how nestjs interceptors work interceptors intercept incoming requests before they reach your controller's route Handler they can perform additional logic before the route Handler is called interceptors also intercept the outgoing response sent to the client allowing you to perform additional Logic on the return value before the whole response is sent back let's say for example we want the client to be able to make a request to the server and get a user back the request reaches the server the controller's route Handler is called and the route Handler gets the user record from the user service the user object return may contain sensitive information we may want to filter out such as a password field you'll find yourself writing the logic to remove the password field somewhere in your controller or service layer this can change the direct responsibility of the original function intended to do a specific operation instead you can use an Interceptor to abstract the additional logic away the Interceptor can take the user return from the route Handler remove the password field and send the user record to the client overall interceptors can do anything you want before any request and response is received let's hop into our nestjs project and Implement one so right now I have a very basic project set up I just generated a new Nest project I didn't do anything except for creating some basic things so that we can get started very quickly you can grab the code from GitHub the link is in the description but if you see right over here I have a simple users module and I have my user service added as a provider and I have my users controller if we look at our users controller we have our API users route set up for this users controller and then I have a get request that is going to handle get requests to API users which is going to return an array of mock users and we can see right over here it's calling the user service that we injected into our user controller and it goes ahead and calls get users so if we look at the user service class right now this method get users just returns mock users which is just an array of these plain JavaScript objects these user types okay and I also have my user class up over here so just a lot of basic things that I just wanted to get out of the way so what we're going to do now is let's go ahead and just make sure everything works first so I'm going to click send you can see I'm getting back my list of users and my server is running as as well just fine obviously so what we're going to do is we're going to create our Interceptor and ideally what I want to do is I want to intercept requests coming into this get request for API users primarily though since we're not really sending any data to our back end to this endpoint and there's really nothing that we need to do when we are handling the request at the moment I want to actually modify the response that is sent back to the client because I don't want the password to be visible to the client that's actually very very bad even if it's hashed you don't want to send the actual password field back so what I'm going to do is inside my users folder right here I'm going to create a new folder called interceptors and all of the interceptors that we create will go inside this folder so I'll create a new file and I'll call it users. Interceptor TTS so every Interceptor in njs is going to be a class so let's create a class and Export it I'll call this class user users Interceptor and we also want to make sure that we use the injectable decorator as well and Mark this as a provider now our user Interceptor needs to implement the nest Interceptor interface okay every Interceptor must implement this interface so the method that we must Implement is this intercept method now this intercept method actually takes a couple of arguments Only Takes Two so not too bad the first argument is the context which is of type execution context and then the second argument is this next argument and the type annotation for this is call Handler like that okay now with the context you can use the context argument to call methods such as get class and this get class method will give you back the actual controller class instance so for example if I were to make a get request to API users well this request pertains to this users's controller and nestjs keeps track of that with the execution context so in the Interceptor when we actually intercept that get request by calling get class it will return to me this users controller class instance okay so I'll just write a simple console log right over here and I'll just reference the name okay so again whatever you need from the context maybe you want to get the Handler so that will get you the get users function because that's our request Handler that's going to be called that'll give you the reference to that you can go ahead and grab it by calling get Handler Okay now what's most important is actually this next argument this next argument is an object that has this handle property which is a method and you can call this method and what this does is it actually just calls the request Handler for that pertaining request inside the controller so again if we make a get request to API users the request Handler that's supposed to be called is this get users method inside our users controller class so this users Interceptor inside The Intercept method when I call next. handle it actually is going to call this get users method again nestjs keeps track of all that for us so we can easily perform these types of abstractions so by calling next. handle it'll go ahead and call get users and it'll perform its necessary business logic in this case it's going to reference this. user service and call get users which will return to us our mock users array and then we want to make sure that we return this next. handle call and that will go ahead and return back to the client that made the request and it will give them the users array okay so let's actually just test this out real quick and see what's going on additionally let me also add some type annotations as well so for the intercept method we can type annotate this because the actual return value is an observable or promise observable like this and observable is imported from rxjs this package is installed by default when you scaffold your nestjs JS project okay of course I'm going to change this type of NE later I'm just going to leave it like that for now I want to first show you what happens when I apply the users Interceptor to my get users request Handler so I'm going to go ahead and right underneath my get decorator I'm going to use the use interceptors decorator and that's imported from nestjs commmon I'm going to go ahead and pass that users's Interceptor class like an argument into us interceptors just like this and we are importing users Interceptor up top over here so watch what's going to happen when I make a request to get API users right over here let me quickly add a console log and I'll just say inside get users Handler and so what you'll see is that when I make a get request to API users the first thing that will happen is it's going to intercept my request with the user interceptor so this interet method gets called and we're going to log the the class name and then it's going to go ahead and call next. handle and then it's going to call this get users method so that's what next. handle does it calls get users it's going to conso log this message over here it's going to go ahead and call the user service get users method return the value return back from get users and then it's going to return it back to the client so I'm going to go into Thunder client right now I'm going to click Send okay and now let's look at the console you can see right over here it is currently logging users controller so that is the class name that's logged inside our intercept method so it is working expectedly and right after it logs the controller name or the class name you can see that it logs whatever I just wrote inside the request Handler function which says inside get users Handler so you can see the order of the logs that are happening so that verifies that the Interceptor is intercepting the request and then calling the request Handler okay so right now we're not doing anything but just writing some logs let's go ahead and actually do something with the response because that's what we can do with interceptors we can not only intercept the request but also intercept the response so right over here this next. handle method call it returns in observable okay and the observable has this pipe method that I can call and I can use this pipe method to apply rxjs operators so for example if I wanted to access the data that's in the observable I can do that if I wanted to apply a transformation of the data I can do that as well so we can use this map operator I'm going to import this from rxjs and then what I can do with this map operator is I can pass a callback function which gets me the data itself as an argument into that callback function and from here I know that data is actually going to be an array of users so I can actually just reference data and I can call any array method I want so I can call map or do filter I'll just return data the way it is right now and then if I click send you can see right now it's going to send me back the users unmodified we didn't do anything with it just yet if I want to I can add a field I can just do data and just return data like this or let me just remove this part cuz we already doing that this is the shorthand syntax if I click send you can see now it's going to actually return an object with this property data and that maps to the array of users okay so you can see how I am transforming the return value so let's actually go ahead and do this first let me actually type annotate call Handler so this tells me what the return type of get users is going to be so we know that get users returns an array of users so first let me import this user class that is from user. TS I created this ahead of time so this is going to be an array of user so now you'll notice that data actually has a type annotation now before it was any but now after adding the type annotation on call Handler data is now properly type annotated to be an array of users let me also just do the same thing for the observable right over here and what I'm going to do is I'm going to go ahead and just remove this part over here and what I'll do very quickly is I'll remove the password field from the user object itself so we can do that very easily like this so I'm going to reference data. map I'm going to call the map method and I'm going to pass a callback function and in that callback function we have an argument which is the user itself I'm going to actually destructure the p password from user and I'm going to pack all of the remaining Fields into this user object right over here so I'm basically extracting password and I'm keeping all of the remaining Fields inside the user object itself you can see when I hover over it we now only have ID username and display name and then I'm just going to return the user itself like this okay right now it's going to complain because obviously we are returning an object or an array of objects that does not contain that password field but let me just actually do this very quickly let me just set this to any very quickly and what I'm going to do is I'm going to go ahead and just make a request now just because I want to show you this example and you can see now when I click Send It Returns the list of users without the password okay now while this does work it's not the way to do it in nestjs so I'll show you how to do it the nestjs way so what I'm going to going to do is install two packages I'm going to install class Transformer and I'm going to install reflect metadata so class Transformer gives me decorators that I can apply on my class fields and reflect metadata is needed to actually use class Transformer so let me run my server again and it's actually very easy to use so what we'll do is we'll go inside the user class that I created and we want to remove this password field from being shown to the client now instead of just entirely removing this password field because we can't do that because we actually need the password field itself to represent our user because obviously we're saving the password to our database or some data source we just want to temporarily or just you know kind of like not expose this field to the client itself so with class Transformer I can use this exclude decorator so that comes from class Transformer right over here and what I can do is I can transform my user instances and whenever we do that it's going to exclude the password field so when we transform those user instances there's this function that we can import from class transformer called plane to instance and I can actually call PLS instance like this and then what I can do is I can pass in the class that I want to transform the object to and then the object itself obviously we don't have the object right now but this is just an example of what the syntax looks like so when we do that it's actually going to create the new object but exclude the password so what we'll do is we'll leave this alone right now let's just go into main.ts we need to import reflect metadata in order for this to work so import it like this inside your main.ts file and then we're going to go into our Interceptor class and instead of doing all this I'm going to go ahead and instead of destructuring these properties I'm going to get the user object and I'm going to go ahead and call this plane to instance function plane to instance like that and so what this will do is it'll convert the literal object so in our case these mock objects cuz these are actually not instances of users these are just plain Json objects okay they're not actually instan of our user class so essentially what we're doing is we're going to convert those plain objects to an actual user instance and then since we have this exclude field right over here or this exclude decorator on the password field it will exclude that password field so first we need to pass the user class as an argument like this notice the capital u right over here and then we're going to go ahead and pass the actual object that we want to convert into the instance so in this case it's our user argument over here okay so we're basically converting user into the user class so hopefully this makes sense now watch what's going to happen when I go and make a request if I click Send you're going to see now I no longer see the password field over here if I remove this exclude decorator and make the request again you're going to see that now I actually see the password in the user object itself so this is how you would do it the quote unquote nestjs Way by using class Transformer instead of just doing what I just did earlier by destructuring the password field and then sending just the remaining object with the remaining Fields so hopefully this makes sense now aside from just modifying the response and sending it back to the client interceptors can also be used to catch errors so let's go ahead and do this I'm going to go ahead into my users controller class and I'll create another method and I'll just call this create user like this I'm going to use the post decorator notice that it's imported from nestjs common and we're not actually going to create a user I'm just going to make a post request to this endpoint and I'm just going to throw an error or an exception so throw new HTTP exception so that's also imported from nestjs commmon up top over here and for the first argument I'm going to pass in the message I'll just say bad request and then status code to 400 so I'm just going to throw an error and I want to show you how we can catch it inside an Interceptor so what I'm going to do is I'm going to go ahead and create a new Interceptor because you can create as many as you want and apply as many as you want to a certain request Handler so what I'll do is I'll create a new file I'll call this errors. Interceptor TTS and going to create a class call it error uh user error Interceptor implements The Nest Interceptor interface and I'll just use autocomplete to complete the uh method implementation like this and let me just use the injectable decorator to mark this Interceptor as an injectable and now let's go ahead and do this so so I'm going to take my user error Interceptor and I want to I want to apply it to this create user request Handler so I'm going to use the use interceptors decorator like we did for our get users method and I'm going to apply the users user error Interceptor so I'm going to import it up top over here and I'm applying that Interceptor to this create user request method Handler okay now what I'm going to do is whenever we actually call this method it's going to throw this HTTP exception so we need to make sure we obviously call that request Handler and we do that by calling next. handle if we don't call this method it's not going to actually call that request Handler and remember that handle returns an observable so I can call this pipe method and then I can use this C error rxjs operator so let's import that from rxjs up top over here and this is also a function as well and then you can use catch error to literally catch the error so what I can do is I can pass this callback function like this and then I can throw an error myself and this is also another operator as well and then what I can do is I can just pass in this other callback function inside throw error and from here on I can literally do whatever I want I can throw a new error of a different type so for example if I so right over here you can see I'm throwing an HTTP exception but if I wanted to throw a different type of exception so let's do HTTP exception let's just do intercepted response and let's send a status go to let's do 500 just as an example okay I know it is going to look redundant but the whole purpose is to show you how the Interceptor intercepts the error that is going to be thrown inside the request Handler function so uh let's go ahead and do this okay um let's go back to here let's make a post request we already appli the errors Interceptor to our endpoint so that's good so so if I click send notice how now instead of our request Handler sending back this status code to 400 and sending back bad request notice how now it actually says status code 500 intercept the response if I were to if I actually remove this pipe right over here this pipe call and if I make the request again you can see now instead of actually intercepting the response or modify find the response cuz it's still intercepting response we're just not doing anything with it it's just going to go ahead and call create user and it's going to let create user throw this error and we're not doing anything at all with the error we're just going to let it return back to the client and then the client will see this as the response so I hope that this shows you that you can actually catch errors inside the Interceptor layer so let's say for example your create user method is going to to perform some side effect such as calling the database or maybe it's going to call an external API using an HTTP client and you don't want to perhaps do a try catch like this to handle your errors instead what you could do is you can actually just call the method and then you can let the Interceptor catch the error if there are any errors at all okay so let's just say if there weren't any errors let's just go ahead and remove this entire call over here okay we're not going to throw any errors at all but we're going to catch them if there are any if I were to click Send right now notice how nothing happens it just sends back a 2011 okay we just assume that it's a valid request and a valid response and you can see that this catch error only works if there is an actual error to be caught so instead of just having our controller layer or service layer handle all of our errors we can literally abstract that away in into the Interceptor layer so hopefully this helps you better understand how powerful nestjs as a framework is if in case you haven't already figured that out because we have so many different abstracted layers that can handle certain things for us and it makes it easy for us to write code that doesn't have to do too much and do too little so now my controller layer can just be responsible for just calling the service layer it doesn't have to worry about handling any errors at all we can pass that responsibility to our Interceptor so I hope that this tutorial made sense to you all I hope you enjoyed it and if you have any other questions feel free to leave a comment down below I also have a Discord server that you can join the link is also in the description check it out you can go ahead and ask any questions that you want regarding programming so I hope those resources help out so that's going to be pretty much it for this tutorial I hope you all enjoyed it and I will see you all in my next episode peace out
Info
Channel: Anson the Developer
Views: 4,307
Rating: undefined out of 5
Keywords: nest js, nest.js, nestjs interceptors
Id: grrAhWnFs9A
Channel Id: undefined
Length: 24min 5sec (1445 seconds)
Published: Fri Dec 22 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.