Angular: Caching service using Http Interceptor
Recently while working on a new project, the need arose for a way to cache just some things (i.e. users mainly) to prevent so many requests to the server for the same information. I was tasked with coming up with a caching system that worked, was expandable and configurable.
While determining the best route to the caching solution I figured the entry point should be in an HTTP Interceptor. We could decide there if we should deliver data from the cache or get it from the server. Also, we wanted some things stored in session storage so those items would be available between refreshes.
Requirements
The following requirements were determined to meet our needs:
- Caching routes should be configurable
- Should include ability to store data locally or in session storage
- Ability to add things to be cached should be easy for the developer
- Should be smart enough to know when to clear an item from the cache
Implementation
First things first, we need a way to configure what should be cached or not. So I created a constant to hold that configuration.
For the object key, this is a route pattern and the value is a boolean which when true will store the cacheable data in session storage. To add something new to be cached, just add a new property here.
Next up is the cache class. The initial thought was that there may be a need to implement other caches elsewhere, but soon came to the realization that this should never be the case. I still left the initial abstract class there in case that decision ever was contested for whatever reason. But here is that class:
I guess let’s start from the top. We’ve got our cache
property. This is just an object where the key is a url with parameters and the value is an HttpRequest
instance. This is where all of the non-session storage items will be stored.
Next is the get
, put
and delete
methods. These do exactly what you think they would do. They get, put and delete things in/from the cache. The biggest part of those methods is determining if the item should be cached and where it should get/put the item. This is accomplished by the shouldCache
and shouldCacheToSessionStorage
methods.
The shouldCache
method checks if the passed in url matches the route pattern defined in the CacheableRoutePatterns
constant. For matching duties I’m using a node module named route-parser. It determines if the url matches the route pattern. If it does, then that request response should be cached.
The shouldCacheToSessionStorage
method checks if the passed in url matches the route, if so just return the value of that item in CacheableRoutePatterns
.
Lastly is the cacheToLocal
and cacheToSessionStorage
methods. These methods just put/delete the response in the appropriate location.
Now, where all this meets the road is in the http interceptor:
This class includes the loading spinner implementation I described in one of my previous articles named “Angular: Loading spinner using Http Interceptor”, so I’m not going to describe that bit of this. When an http request happens, we check what type of request it is. If it’s a GET request, we attempt to get the url defined in the request from the cache. If we get something, we just return it. If the request is a PUT, POST, PATCH or DELETE, we remove the url defined in the request from the cache. Lastly, once we get a response we put the response in the cache. Since the `HttpCacheService` class determines if something should be cached or not, there is no need to include that check here.
Wrapping Up
So, there we have it. A fairly robust caching implementation that once created is pretty much just a set it and forget it feature that just works.
Shameless Plug
If you like this I have created an Angular Boilerplate/Starter kit project that is for getting an Angular application up and running fast. It includes the http caching and loading spinner services plus some other things that most apps today may/may not need. If you think it’s missing something, send me a pull request and we’ll check it out.
Until next time…. Happy Coding.