Luis
Luis

Reputation: 6001

Should I use Service or Factory for my $http interceptor

I need to implement an interceptor for the $http service. I have tried 2 implementations using a factory and a service, they both work OK. this is the implementation in type script:

Service:

 export class AuthInterceptorService {

    private _authService:Services.IAuthService;

    static $inject = ['$q', '$location', '$injector'];  

    constructor(private $q: ng.IQService, private $location: ng.ILocationService, private $injector: ng.auto.IInjectorService) {

    }

    private getAuthService = (): Services.IAuthService=> {
        if (this._authService == null) {
            this._authService = this.$injector.get('authService');
        }
        return this._authService;
    }

    public request = (config: ng.IRequestConfig) => {
        config.headers = config.headers || {};
        var authData = this.getAuthService().authData;
        if (authData) {
            config.headers.Authorization = 'Bearer ' + authData.token;
        }
        return config;
    }

    public responseError = (rejection)=> {
        if (rejection.status === 401) {
            this.getAuthService().logOut();
        }
        return this.$q.reject(rejection);
    }
}

In app init:

.service('authInterceptorService', Services.AuthInterceptorService)

Factory:

export function AuthInterceptorFactory($q: ng.IQService, $injector: ng.auto.IInjectorService) {

    return {
        request: (config: ng.IRequestConfig)=> {
            config.headers = config.headers || {};
            var authData = $injector.get('authService').authData;
            if (authData) {
                config.headers.Authorization = 'Bearer ' + authData.token;
            }
            return config;
        },

        responseError: (rejection)=> {
            if (rejection.status === 401) {
                $injector.get('authService').logOut();
            }
            return $q.reject(rejection);
        }
    };
}

In app init:

.factory('authInterceptorFactory', ['$q', '$injector', Services.AuthInterceptorFactory])

and then on configuration of the interceptor:

.config(['$httpProvider', ($httpProvider:ng.IHttpProvider) => {
    $httpProvider.interceptors.push('authInterceptorxxxxx');
}])

As you can see I am using the service location pattern to inject a dependency (using $injector), this is to avoid a circular dependency since the injected service has a dependency on $http.

As I said they both work, I prefer the Service version as it allows me to cache the injection of the dependent service 'authService', in the factory flavour it gets resolved and injected all the time on every request. Is there any problems in using the Service implementation? in Angular docs they refer you should use a factory.

Upvotes: 1

Views: 1229

Answers (1)

basarat
basarat

Reputation: 276353

There is nothing wrong with using a service for an HttpInterceptor. Angular will simply call injector.get to resolve it, so using a service is fine.

From source $injector.get(interceptorFactory) https://github.com/angular/angular.js/blob/6f19a6fd33ab72d3908e3418fba47ee8e1598fa6/src/ng/http.js#L207-L210:

 forEach(interceptorFactories, function(interceptorFactory) {
      reversedInterceptors.unshift(isString(interceptorFactory)
          ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
    });

Upvotes: 2

Related Questions