Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 4 - HTTP Interceptor

Tags:

angular

I'm trying to create HTTP Interceptor in Angular 4 but I'm having some weird error. Following is my error:

Argument of type 'Observable<Response>' is not assignable to parameter of type 'Observable<Response>'.

Following is my Code:

import { Injectable } from '@angular/core';
import { Http, ConnectionBackend, RequestOptions, RequestOptionsArgs } from '@angular/http';
import { Router } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import * as _ from 'lodash';

@Injectable()
export class HttpInterceptor extends Http {

    constructor(backend: ConnectionBackend, defaultOptions: RequestOptions, private _router: Router) {
        super(backend, defaultOptions);
    }

    request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
        return this.intercept(super.request(url, options)); // Here is the error
    }

    get(url: string, options?: RequestOptionsArgs): Observable<Response> {
        return this.intercept(super.get(url, options)); // Here is the error
    }

    post(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> {
        return this.intercept(super.post(url, body, this.getRequestOptionArgs(options))); // Here is the error
    }

    put(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> {
        return this.intercept(super.put(url, body, this.getRequestOptionArgs(options))); // Here is the error
    }

    delete(url: string, options?: RequestOptionsArgs): Observable<Response> {
        return this.intercept(super.delete(url, options)); // Here is the error
    }

    getRequestOptionArgs(options?: RequestOptionsArgs): RequestOptionsArgs {
        if (options == null) {
            options = new RequestOptions();
        }
        if (options.headers == null) {
            options.headers = new Headers(); // Here is the error
        }
        options.headers.append('Content-Type', 'application/json');
        return options;
    }

    intercept(observable: Observable<Response>): Observable<Response> {
        return observable.catch((err, source) => {
            if (err.status == 401 && !_.endsWith(err.url, 'api/auth/login')) {
                this._router.navigate(['/login']);
                return Observable.empty();
            } else {
                return Observable.throw(err);
            }
        });

    }

}

Does anyone know what is going wrong here? I tried debugging for 3 hours but unable to find any clue.

Edit:

I also tried to remove everything and written a code like this:

request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
    return super.request(url, options);
}

But still it's giving same error:

Argument of type 'string | Request' is not assignable to parameter of type 'string | Request'. Type 'Request' is not assignable to type 'string | Request'.

like image 636
Sahil Purav Avatar asked Jun 06 '17 18:06

Sahil Purav


People also ask

What is HTTP interceptors in angular?

HTTP Interceptors is a special type of angular service that we can implement. It's used to apply custom logic to the central point between the client-side and server-side outgoing/incoming HTTP request and response. Keep in mind that the interceptor wants only HTTP requests.

When implementing an HTTP interceptor which method must be provided?

To implement an interceptor, you'll want to create a class that's injectable and that implements HttpInterceptor. The intercept method takes two arguments, req and next, and returns an observable of type HttpEvent. req is the request object itself and is of type HTTP Request.

Can I have multiple HTTP interceptors in angular?

So how can I add multiple interceptors? Http doesn't allow to have more than one custom implementation. But as @estus mentioned the Angular team has added a new HttpClient service recently (release 4.3) which supports multiple interceptors concept. You don't need to extend the HttpClient as you do with the old Http .


4 Answers

Http interceptor is already implemented in Angular 4.3.4 and is described in the documentation.

You need to implement the intercept method of HttpInterceptor interface, do something with the request, and call the next.handle(req) method.

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

@Injectable()
export class NoopInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const changedReq = req.clone({headers: req.headers.set('My-Header', 'MyHeaderValue')});
    return next.handle(changedReq);
  }
}

It's also necessary to register interceptor in app's providers section

import {NgModule} from '@angular/core';
import {HTTP_INTERCEPTORS} from '@angular/common/http';

@NgModule({
  providers: [{
    provide: HTTP_INTERCEPTORS,
    useClass: NoopInterceptor,
    multi: true,
  }],
})
export class AppModule {}
like image 165
akn Avatar answered Oct 16 '22 17:10

akn


akn's answer is the right one. I was trying to make it work with http service, but the interceptor only works whit httpClient service.

import { HttpClient } from '@angular/common/http';

constructor(private http: HttpClient) { }
like image 27
Daniel Delgado Avatar answered Oct 16 '22 17:10

Daniel Delgado


The globally available DOM typings ("lib": ["dom"] in your tsconfig) include Response and Request interfaces that are unrelated to the types used by Angular.

You need to import Response and Request from @angular/http.

like image 4
dbandstra Avatar answered Oct 16 '22 19:10

dbandstra


The following instruction worked for me perfectly:

In the app module:

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

@NgModule({
    imports: [
...
    HttpClientModule,
  ],
  providers: [{
    provide: HTTP_INTERCEPTORS,
    useClass: MyInterceptor,
    multi: true
  }],
  bootstrap: [AppComponent]
})

In the interceptor:

import { Injectable } from '@angular/core';

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

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/do';
import { HttpErrorResponse } from '@angular/common/http';
import { RequestOptions } from '@angular/http';
import { HttpHeaders } from '@angular/common/http';

@Injectable()
export class MyInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    // when there is POST request
    if (req.method === 'POST') {
      const content_type = 'application/x-www-form-urlencoded';
      const req= req.clone({
        headers: req.headers.set('Content-Type', content_type),
        body: 'my body'
      });

      return next.handle(accessReq);
    }
  }
}

IMPORTANT: http should be an instance of HttpClient!

constructor(
    private http: HttpClient, private accessTokenService: AccessTokenService
) { }
    return this.http.post(ingestURL, null)
        .map(res => {
            return res; // data returned from interceptor
        });
like image 3
Enayat Avatar answered Oct 16 '22 17:10

Enayat