DEV Community

Parth Shukla
Parth Shukla

Posted on

Cache Interceptor in Angular

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,
    }
  ],
  ...
})
Enter fullscreen mode Exit fullscreen mode

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);
            }
        }));
  }
}
Enter fullscreen mode Exit fullscreen mode

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);
  }
}
Enter fullscreen mode Exit fullscreen mode

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 }
    );
  }
Enter fullscreen mode Exit fullscreen mode

Top comments (0)