Alex91ckua
Alex91ckua

Reputation: 87

Custom Http service in Angular2. Cyclic dependency error

I've created custom Http service to override "request" method which updates token on each request if it's required. But problem is that I'm receiving "Cyclic dependency" error. Any idea how to fix?

Custom Http service:

import { Injectable } from '@angular/core';
import {
    Request, XHRBackend, RequestOptions, Response, Http, RequestOptionsArgs, Headers } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
import {UserService} from "../services/user.service";

@Injectable()
export class VodHttpService extends Http {

    constructor(backend: XHRBackend, defaultOptions: RequestOptions, private userService : UserService ) {

        super(backend, defaultOptions);
    }

    request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {

        //adding access token to each http request before calling super(..,..)
        let token = this.userService.token;
        if (typeof url === 'string') {
            if (!options) {
                options = { headers: new Headers() };
            }

            if ( url != this.userService.PUBLIC_TOKEN_URL ) {
                options.headers.set('Authorization', `Bearer ${token}`);
            }
        }
        else {

            if ( url.url != this.userService.PUBLIC_TOKEN_URL ) {
                url.headers.set('Authorization', `Bearer ${token}`);
            }
        }

        console.log(url);

        return super.request(url, options)
            .catch((error) => {
                //if got authorization error - try to update access token
                if (error.status = 401) {
                    return this.userService.updateToken()
                        .flatMap((result: boolean) => {
                            //if got new access token - retry request
                            if (result) {
                                return this.request(url, options);
                            }
                            //otherwise - throw error
                            else {
                                return Observable.throw(new Error('Can\'t refresh the token'));
                            }

                        })
                }
                else {
                    Observable.throw(error);
                }
            })

    }

}

My singleton user service is looking like:

import {Component, Injectable, Injector} from '@angular/core';
import {Http} from "@angular/http";
import {Observable} from "rxjs";
import {environment} from "../../environments/environment";

@Injectable()
export class UserService {

    public token : string;
    public PUBLIC_TOKEN_URL = environment.token_url;

    constructor (private _http: Http) { }

    updateToken() : Observable<boolean> {

        let url = this.PUBLIC_TOKEN_URL;

        return this._http.get(url).map( res => {

            // return res.json();
            if (typeof res.json().access_token !== 'undefined'){

                this.token = res.json().access_token;
                return true;
            } else {

                return false;
            }
        });
    }

}

I know where is way to fix it by using Injector but I think it's ugly method.

Upvotes: 1

Views: 246

Answers (1)

Andrei Matracaru
Andrei Matracaru

Reputation: 3671

The provider definition for your custom VodHttpService is not correct. It should be something like this:

export function vodHttpFactory(backend: XHRBackend, options: RequestOptions, userService: UserService) {
      return new VodHttpService(backend, options, userService);
    }

@NgModule({
// other stuff 
providers: [ 
    UserService,
    {
      provide: VodHttpService,
      useFactory: vodHttpFactory,
      deps: [XHRBackend, RequestOptions, UserService]
    }
  ]
})

Note that the vodHttpFactory function is written like that to be compatible with AOT, in case you need it.

Upvotes: 1

Related Questions