简体   繁体   中英

How do I ensure operators on an observable occur after a HTTP Interceptor?

In my Angular 8 application, I have a basic caching interceptor:

export class CacheInterceptor implements HttpInterceptor {

  constructor(private cache: CacheService) {}

  public intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    if (req.method !== 'GET') {
      return next.handle(req);
    }
    const cachedResponse = this.cache.get(req);
    if (cachedResponse) {
      console.log(cachedResponse);
      return of(cachedResponse);
    }

    return next.handle(req).pipe(
      filter(event => event instanceof HttpResponse),
      map((response: HttpResponse<any>) => {
        this.cache.addToCache(req, response);
        return response;
      })
    );
  }
}

I also have a service which retrieves data from an external API:

  public getCases(options: ModuleArguments): Observable<CaseResponse> {
    return this.http
      .get<CaseResponse>(this.URL_BASE, {
        params: options as HttpParams
      })
      .pipe(map(this.cleanData, this));
  }

The 'cleanData' method just loops through the received data and amends some of the values to make them more human friendly (eg turns 'support_request' to 'Support Request').

What appears to be happening is the response is being added to the cache by the CacheInterceptor after the data has been 'cleaned' within the service. Therefore, when the same request is made again, and received from the cache, the service is attempting to clean data which has already been cleaned.

How do I ensure that the the HTTP Response has been intercepted and added to the cache before it has been amended by the service?

How about you approach this by moving the pipe(map(this.cleanData, this)) operation to the point when the Observable has completed and returned your CaseResponse . Likely, this will mean that the HttpInterceptor has been applied first.

ie In the place where you invoke getCases you could try something like this:

service.getCases(options).subscribe(resolvedData => {
   // assuming cleanData(data: CaseResponse) signature
   const cleanedData = this.cleanData(resolvedData);  

   // .. do something with cleanedData 
});

Also, from a design perspective, you wouldn't want getCases to do more than exactly what it's supposed to - It's a service method that performs an HTTP request and returns the cases in the format they are sent to you. The reformatting of the data could be ideally done at the consumer of that service function - as it's very likely the consumer that needs it cleaned/reshaped .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM