Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Injector Error "Provider parse errors: Cannot instantiate cyclic dependency!"

Tags:

angular

I tried to create an HttpInterceptor to add some headers for authorization to every http that happens. I need to get the headers from a service called AuthService. Here is the code below:

Interceptor:

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

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  constructor(private auth: AuthService) { }
}

AuthService:

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

@Injectable()
export class AuthService {
  constructor(private http: HttpClient) { }
}

AppModule:

providers: [{
    provide: HTTP_INTERCEPTORS,
    useClass: AuthInterceptor,
    multi: true,
  }, AuthService]

I receive the following error:

Error: Provider parse errors: Cannot instantiate cyclic dependency! InjectionToken_HTTP_INTERCEPTORS ("[ERROR ->]"): in NgModule AppModule in ./AppModule@-1:-1

I already checked the previous answers but I don't understand where the cyclic dependency was detected. What I am trying to do is described here: https://angular.io/guide/http#setting-new-headers

like image 455
itsundefined Avatar asked Aug 12 '17 19:08

itsundefined


3 Answers

Look at this GitHub Discussion (Issue #18224)

As a workaround you can use Injector manually and inject relevant service inside intercept method: https://github.com/angular/angular/issues/18224#issuecomment-316957213

I resolved simply not setting authService in constructor but getting in the intercept function.

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    // Get the auth header from the service.
    const auth = this.inj.get(AuthenticationService);
    const authToken = auth.getAuthorizationToken();
    ...
}

UPDATE:

Prior to Angular 4.3.0 unfortunately it's impossible to use Injector manually inside intercept method:

ERROR Error: Uncaught (in promise): RangeError: Maximum call stack size exceeded

So there is one more workaround using rxjs:

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return Observable.create((observer: any) => {
        setTimeout(() => {
            const authService = this.injector.get(AuthenticationService)
            observer.next(authService.getAuthorizationHeader())
            observer.complete()
        })
    })
        .mergeMap((Authorization: string) => {
            let authReq = req

            if (Authorization) {
                authReq = req.clone({
                    setHeaders: {
                        Authorization
                    }
                })
            }

            return next.handle(authReq)
        })
}
like image 111
oleh.meleshko Avatar answered Nov 07 '22 12:11

oleh.meleshko


Remove AuthService from providers list as it is imported in the Interceptor already thus the cyclic dependency.

like image 6
Vega Avatar answered Nov 07 '22 12:11

Vega


Remove following from AuthService -

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

The reason is - HttpClient using interceptor internally and interceptor using AuthService and AuthService is using HttpClient. thus it gives "cyclic dependency" error.

like image 3
Kanchan Avatar answered Nov 07 '22 10:11

Kanchan