Project Setup
The repo with the app referenced in this post is here: GitHub — VicAv99/http-interceptors.
If you want to skip the sections about the code and its uses, please skip to the Basic Example and Implementation section.
Below you will find quick steps to get started with the example app to follow/explore along:
You will now see the application at http://localhost:4200 and the JSON Server running at http://localhost:3000/tasks.
The HttpInterceptor
Note: The idea of this post is to take a simple example, understand what the example is doing, and find exactly how we can apply that to real-life, larger problems in future projects. Isolated examples, using “cmd + click” to get more detail on a package, and brief but precise explanations can go a long way when faced with bigger problems.
Before getting started with the actual code and implementation of our interceptors, let’s take a quick dive into what the Angular HttpInterceptors actually are.
Interceptors, like much of Angular, are just classes. However, the class we create must implement the Angular HttpInterceptor interface. When digging into the type definitions, we see that this interface describes a function named "intercept."
The intercept function takes two arguments, req and next. These arguments also have interfaces applied to them which we use to return some sort of HttpEvent Observable. First, we’ll expand on what the req argument is bringing in. As a brief explanation, an HttpRequest holds any outgoing HTTP request executed by the HttpClient. Another quick look into the type definitions, you will see that included in this request are the URL, method, headers, body, and other request configuration options. This means that this interceptor receives the request and all of its attached properties before sending it off to your server (our JSON Server in this case). The second argument (next) is a class with an abstract method called handle. Depending on whether or not you are using multiple interceptors, this method will send its response to the next interceptor, or the backend if none. Cool!
So to sum it up, we have all of the information we could want about what we are sending back to our server via the HttpClient and then passing that down the chain of interceptors until we finally send this off to our backend server. Knowing this information, we can make some awesome things happen.
Basic Example and Implementation
The example we’re using is a task app to plan our day. The app's developers have hidden some cool features in the form of a HttpInterceptor. These features convert the word “pizza” to a pizza emoji, and if you reach a task that is a blocker, a notification will be sent to remind you that others are there to help. Let’s take a look at the BlockerInterceptor feature:
Above is a function named "notify," which briefly opens the Angular Material Snackbar to display a message. Inside the intercept function, we are checking to see if the request has a body being sent to our server and if the body has a property blocker marked as true. If these criteria are met, the notify method will take effect for three seconds (3000 milliseconds), and the interceptor will continue on and pass down the request.
Hook Up The Interceptor
As you may have noticed, the interceptor feature uses Angular’s @Injectable decorator just like a service. So now, the only thing to infer here is the need for our custom interceptor to be imported into our app module and included in the providers. However, the class needs to be provided to the app in a little different format than what we are used to. Take a look at our app modules providers now:
For the interceptor to be properly provided, an object with three properties inside of it has to be created. First, add provide, which will listen for the HTTP_INTERCEPTORS token representing the array of HttpInterceptors being used. Once the token is added to the “provide” property, the object checks to see what Class it will use for our Interceptor. The BlockerInterceptor class is imported to the model and included in the useClass property of the object. As implied, the app will use multiple interceptors, so multi is set to true.
Aside: This approach will only work for applications not using the module per feature or lazy loading. If your app does have either as its architecture, you will have to provide as a per module basis.
Modifying HTTP Requests
What about the PizzaInterceptor? The best has been saved for last. Since this is a more “relatable” example of what HttpInterceptors can do, you can apply what you see here and think about ways to streamline your workflows. For example, say you have an access token that needs to append to each request header you are sending, or you’re getting XML data that needs to be converted to JSON. Doing all that manually is a pain, but with interceptors, you can do this globally and pain-free.
Here, we are grabbing the request body we are sending back and restructuring it to get just the description property (what we see as our task). Then we use some simple regex that globally looks for the word pizza then we use JavaScript’s replace method to switch out the word pizza for the pizza emoji 🍕. As for the typings, we looked at an earlier state, to modify the HttpRequest, we use the clone method to pass in our new description containing the 🍕emoji. We then return next.handle(pizzaRequest) and send that down our interceptor chain. Below is our finished app module with our custom pizza interceptor: