3

I am using http Interceptor to intercept each http request in my application. But I am getting Circular dependency found: $http <- APIInterceptor <- $http <- $templateRequest <- $compile

here is my Service code:

mPosServices.factory('mosServiceFactory', function ($http, $rootScope, $cookies, $q) {
    return{
         refresh_token: function () {
            var refreshToken = $http({
                method: "get",
                url: "myservice/oauth/token?grant_type=refresh_token&client_id=restapp&client_secret=restapp&refresh_token=" + $cookies.get('refresh_token'),
            })
            return refreshToken;
        }
});

mPosServices.service('APIInterceptor', ['mosServiceFactory','$cookies',function (mosServiceFactory,$cookies) {
        var service = this;
        service.request = function (config) {
            if (!$cookies.get('access_token')) { //if access_token cookie does not exist
               mosServiceFactory.refresh_token().then(function (response) {
                    var date = new Date();
                    date.setTime(date.getTime() + (response.data.expiresIn * 1000));
                    $cookies.remove('access_token');
                    $cookies.put('access_token', response.data.value, {expires: date});
                    $cookies.put('refresh_token', response.data.refreshToken.value);
                }); //call the refresh_token function first
            }
            return config;
        };

        service.responseError = function (response) {
            return response;
        };
    }]);

and pushing it as:

$httpProvider.interceptors.push('APIInterceptor');

in config function. Am I doing something wrong here? Even I tried to inject $http manually using

$injector

, but getting same error. Kindly Help me.

user1608841
  • 2,455
  • 1
  • 27
  • 40
  • I find that `$injector.get('$http')` called from within the `service.responseError` function definition avoids the circular dependency error. – JellicleCat Oct 26 '20 at 22:57

1 Answers1

4

You indeed need to add use $injector to get mosServiceFactory instance inside of interceptor. But this is not all you need to do. You also need to make sure you don't fall into infinite request loop because interceptor also makes a request. What you can do is to check if current request is the one for token refresh and if so don't fire one more request, I'm checking the URL for this.

One more important thing to mention. You need to return promise object from interceptor which resolves to original request config. This way it guaranties that intercepted request will be reissued after token is retrieved.

All together will look like this:

mPosServices.service('APIInterceptor', ['$injector', '$cookies', function($injector, $cookies) {
    var service = this;
    service.request = function(config) {
        if (!$cookies.get('access_token') && config.url.indexOf('myservice/oauth/token?grant_type=') === -1) {
            return $injector.get('mosServiceFactory').refresh_token().then(function(response) {
                var date = new Date();
                date.setTime(date.getTime() + (response.data.expiresIn * 1000));
                $cookies.remove('access_token');
                $cookies.put('access_token', response.data.value, {
                    expires: date
                });
                $cookies.put('refresh_token', response.data.refreshToken.value);
            }).then(function() {
                return config; // <-- token is refreshed, reissue original request
            });
        }
        return config;
    };

    service.responseError = function(response) {
        return response;
    };
}]);

Check the demo I was testing solution on to see how it recovers original request after token is loaded.

Demo: http://plnkr.co/edit/1Aey2PThZQ4Y8IRZuVOl?p=preview

dfsq
  • 191,768
  • 25
  • 236
  • 258
  • thumbs up for the demo. Great answer – nalinc Jun 26 '15 at 07:06
  • @dfsq is there any way to bypass route request in iterceptor ? – user1608841 Jun 30 '15 at 05:58
  • 1
    You can check if `grant_type` GET parameter is present in request instead. But you anyway need to check if current request is for token refresh so that you don't issue one more request,. – dfsq Jun 30 '15 at 06:08
  • Am I missing something or is that sescond `then(function()` not going to work because you're not returning a promise in the first `then` block? – Z2VvZ3Vp Dec 01 '15 at 00:30