Angular 4.3 HttpClient : Intercept response

JavascriptAngularHttpInterceptor

Javascript Problem Overview


In the documentation about the new HttpClientModule included in the new version of Angular 4.3, the mechanism to intercept requests is explained very well. There is also mention of the response interceptor mechanism however I cannot find anything about it.

Does anyone have an idea about how to intercept a response in order to modify the body message before it is sent to the service?

Thanks.

Javascript Solutions


Solution 1 - Javascript

I recently made an HttpInterceptor in order to resolve cyclical references in some JSON on the client side, essentially replacing any object with a $ref property with the object in the JSON that has a matching $id property. (This is the output you get if Json.Net is configured with PreserveReferencesHandling.Objects and ReferenceLoopHandling.Ignore).

The answers here helped me some of way, but none of them show how to modify the body of the response, like the OP needs. In order to do so, one needs to clone the event and update the body, like so:

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
	return next.handle(req).map(event => {
		if (event instanceof HttpResponse && shouldBeIntercepted(event)) {
			event = event.clone({ body: resolveReferences(event.body) })
		} 		  
		return event;
	});
}

Any event that should not be modified is simply passed through to the next handler.

Solution 2 - Javascript

I suppose you can use do as @federico-scamuzzi suggested, or you can use map and catch like so:

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

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    console.info('req.headers =', req.headers, ';');
    return next.handle(req)
      .map((event: HttpEvent<any>) => {
        if (event instanceof HttpResponse && ~~(event.status / 100) > 3) {
          console.info('HttpResponse::event =', event, ';');
        } else console.info('event =', event, ';');
        return event;
      })
      .catch((err: any, caught) => {
        if (err instanceof HttpErrorResponse) {
          if (err.status === 403) {
            console.info('err.error =', err.error, ';');
          }
          return Observable.throw(err);
        }
      });
  }
}

EDIT: @LalitKushwah was asking about redirecting if(!loggedIn). I use Route Guards, specifically:

import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot
       } from '@angular/router';

import { Observable } from 'rxjs/Observable';

import { AuthService } from '../../api/auth/auth.service';
import { AlertsService } from '../alerts/alerts.service';

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private router: Router,
              private alertsService: AlertsService) {}

  canActivate(next: ActivatedRouteSnapshot,
              state: RouterStateSnapshot
              ): Observable<boolean> | Promise<boolean> | boolean {
    if (AuthService.loggedIn()) return true;

    const url: string = state.url;

    this.alertsService.add(`Auth required to view ${url}`);
    this.router
      .navigate(['/auth'], { queryParams: { redirectUrl: url } })
      .then(() => {});
    return false;
  }
}

Then I can simply add that as an argument to my route:

{
  path: 'dashboard', loadChildren:'app/dashboard/dashboard.module#DashboardModule',
  canActivate: [AuthGuard]
}

Solution 3 - Javascript

Since Angular 6 release, RxJs 6.0 changed its interface, so you cannot use operators the same way (like .map(), .tap()...).
Because of that, most of the above solutions are outdated.
This is how you correctly modify content of an Observable using RxJs 6.0+ (with pipe):


import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse} from '@angular/common/http';
import {Injectable} from '@angular/core';
import {Observable} from 'rxjs';
import {map} from 'rxjs/operators';




@Injectable()
export class ResponseInterceptor implements HttpInterceptor {



intercept(req: HttpRequest<any>, next: HttpHandler): Observable&lt;HttpEvent&lt;any>> {

    return next.handle(req).pipe(map((event: HttpEvent&lt;any>) => {
        if (event instanceof HttpResponse) {
            event = event.clone({body: this.modifyBody(event.body)});
        }
        return event;
    }));

}

private modifyBody(body: any) {
    /*
    * write your logic to modify the body
    * */
}




}

}

Solution 4 - Javascript

From what i can understand (I've only done the intercept for request and inject auth token) .. you can attach a .do() and test if is a reponse .. like (as doc says):

import 'rxjs/add/operator/do';
 
export class TimingInterceptor implements HttpInterceptor {
  constructor(private auth: AuthService) {}
 
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
  	const started = Date.now();
    return next
      .handle(req)
      .do(event => {
        if (event instanceof HttpResponse) { //<-- HERE
          const elapsed = Date.now() - started;
          console.log(event} ms.`);
        }
      });
  }

}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionolivier houssinView Question on Stackoverflow
Solution 1 - JavascriptsigbjornloView Answer on Stackoverflow
Solution 2 - JavascriptA TView Answer on Stackoverflow
Solution 3 - Javascriptimal hasaranga pereraView Answer on Stackoverflow
Solution 4 - Javascriptfederico scamuzziView Answer on Stackoverflow