Cache Interceptor in Angular
Published: 2022-09-04 15:33:03

In previous blog we have explained what are Interceptors in Angular and gave example of an basic auth interceptor,
In this one we are going to learn how add multiple Interceptors and what are catching Interceptors.

Please have a quick read of the first blog for context,

Now in order to add multiple Interceptors, we first add them in root module file 

```
import {HTTP_INTERCEPTORS, HttpClientModule} from '@angular/common/http';
...

@NgModule({
  ...
  imports: [
    ... ,
    HttpClientModule
  ],
  providers: [
    ... ,
    {
      provide: HTTP_INTERCEPTORS,
      useClass: InterceptorOne,
      multi: true,
    },
    {
      provide: HTTP_INTERCEPTORS,
      useClass: InterceptorTwo,
      multi: true,
    }
  ],
  ...
})
```

**Note** : InterceptorOne and InterceptorTwo are just examples and you have to add your own interceptor class instead of it.



Now we implement our caching Interceptor 

This interceptor caches the request only when the headers contains cacheRequest parameter to true.

```
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';

import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs';
import { tap } from 'rxjs/operators';
import { CacheService } from './cache.service';

@Injectable()
export class CachingInterceptor implements HttpInterceptor {

  constructor(private readonly cacheService: CacheService) {
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    // Don't cache if it's not a GET request
    if (req.method !== 'GET') {
      return next.handle(req);
    }

    // delete cache if no header is set by service's method
    if (!req.headers.get('cacheRequest')) {
      if (this.cacheService.cacheMap.get(req.urlWithParams)) {
        this.cacheService.cacheMap.delete(req.urlWithParams);
      }

      return next.handle(req);
    }

    // Checked if there is cached data for this URI
    const cachedResponse = this.cacheService.getFromCache(req);
    if (cachedResponse) {
      // In case of parallel requests to same URI,
      // return the request already in progress
      // otherwise return the last cached data
      return (cachedResponse instanceof Observable) ? cachedResponse : of(cachedResponse.clone());
    }

    // If the request of going through for first time
    // then let the request proceed and cache the response
    return next.handle(req)
        .pipe(tap(event => {
            if (event instanceof HttpResponse) {
                this.cacheService.addToCache(req, event);
            }
        }));
  }
}
```


**Cache Service** : To store and retrieve for caches

```
import { HttpRequest, HttpResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';

@Injectable()
export class CacheService  {
  cacheMap = new Map<any, any>(null);

  getFromCache(req: HttpRequest<any>): HttpResponse<any> | undefined {
    const url = req.urlWithParams;
    const cached = this.cacheMap.get(url);

    if (!cached) {
      return undefined;
    }

    return (this.cacheMap.get(url)).response;
  }

  addToCache(req: HttpRequest<any>, response: HttpResponse<any>): void {
    const url = req.urlWithParams;
    const entry = { url, response, addedTime: Date.now() };
    this.cacheMap.set(url, entry);
  }
}
```


Sample Get request

```
getMethod(int param1, cache = false): any {
    let headers: HttpHeaders;
    if (cache) {
      headers = new HttpHeaders({ 'cacheRequest': 'true' });
    }

    return this.http.get(
      'http://apiUrl',
      { headers }
    );
  }
```