29

I know how to intercept ALL requests, but I only want to intercept requests from my resources.

Does anyone know how to do this?

services.config(['$httpProvider',function($httpProvider) {
    $httpProvider.interceptors.push('myHttpInterceptor');
}]);

services.factory("userPurchased", function ($resource) {
    return $resource("/api/user/purchases/:action/:item", 
        {}, 
        {
            'list': {method: 'GET', params: {action: 'list'}, isArray: false},
            'save': {method: 'PUT', params: {item: '@item'}},
            'remove': {method: 'DELETE', params: {item: '@item'}},
        }
    );
});

services.factory('myHttpInterceptor', function($q,$rootScope) {
    // $rootScope.showSpinner = false;
    return {

      response: function(response) {
        $rootScope.showSpinner = false;
        // do something on success
        console.log('success');
        console.log('status', response.status);
        //return response;
        return response || $q.when(response);
      },

     responseError: function(response) {
        // do something on error
        $rootScope.showSpinner = true;
        console.log('failure');
        console.log('status', response.status)
        //return response;
        return $q.reject(response);
      }
    };
  });
jrutter
  • 3,173
  • 9
  • 42
  • 51

7 Answers7

24

If you want to intercept only requests from specific resources, you can use optional interceptor property of $request action. Angular's documentation see here (Usage>actions)

JavaScript

angular.module('app', ['ngResource']).
  factory('resourceInterceptor', function() {
    return {
      response: function(response) {
        console.log('response intercepted: ', response);
      }
    }
  }).
  factory('resourceService', ['$resource', 'resourceInterceptor', function($resource, resourceInterceptor) {
    return $resource(":name", 
        {}, 
        {
            'list': {method: 'GET', isArray: false, interceptor: resourceInterceptor}
        }
    );
  }]).
  run(['resourceService', '$http', function(resourceService, $http) {
    resourceService.list({name: 'list.json'}); // <= intercepted
    $http.get('list.json'); // <= not intercepted
  }]);

Plunker: http://plnkr.co/edit/xjJH1rdJyB6vvpDACJOT?p=preview

Vadim
  • 8,701
  • 4
  • 43
  • 50
  • This is not working when i push multiple interceptors to httpProvider. I want to call only a sepecific interceptor, which i am doing as above , but the request method gets called of all the interceptors i registered. – Sanket Dec 28 '15 at 10:36
23

The only way I know of doing this it to just filter out the requests you want in the response handler.

e.g.

...
response: function(response) {
    if(response.config.url.startsWith('/api/')) {
        //Do your custom processing here
    }

    return response;
}
...

Polyfill for string.startsWith()

//Taken from http://stackoverflow.com/questions/646628/javascript-startswith
if (typeof(String.prototype.startsWith) === 'undefined') {
    String.prototype.startsWith = function(str) {
        return this.slice(0, str.length) === str;
    };
}
rob
  • 17,995
  • 12
  • 69
  • 94
  • 3
    If you're using direct urls, good old `indexOf('/api/') > -1` should also work – Tukkan Feb 10 '16 at 13:30
  • This answer works only if the rest api is well named using '/api/'. I prefer checking http header for content-type (such as XML or JSON) – Yacine MEDDAH Jul 01 '16 at 13:33
1

My preferred way is to use an HTTP interceptor which replaces a "magic" Authorization header with the current OAuth token. The code below is OAuth specific, but remedying that is a simple exercise for the reader.

// Injects an HTTP interceptor that replaces a "Bearer" authorization header
// with the current Bearer token.
module.factory('oauthHttpInterceptor', function (OAuth) {
  return {
    request: function (config) {
      if (config.headers.Authorization === 'Bearer') {
        config.headers.Authorization = 'Bearer ' + btoa(OAuth.accessToken);
      }
      return config;
    }
  };
});

module.config(function ($httpProvider) {
  $httpProvider.interceptors.push('oauthHttpInterceptor');
});
Ben Walding
  • 4,006
  • 2
  • 30
  • 28
  • 1
    This doesn't really answer the question which was asked – Squiggle Jun 22 '16 at 07:10
  • It does - just supply an `Authorization` header of "Bearer" / "magic string" with your requests (and no others), and the interceptor will be called. You could use the accepted answer - and this is probably more obvious - but will mean that you're tying that interceptor in everywhere - whereas the method in my example offers indirection. – Ben Walding Jun 25 '16 at 06:53
0
/**object single interceptor**/ 
 function SingleCallInterceptor(callbacks){

    this.receive=function(response) {

      switch (response.status) {

        case 200:

          callbacks.success(apiResponse);

          break;

        default :

          callbacks.error(response);
      }

    }

  }


var successfn=function(response){  //i have my response}

var errorfn=function(response){  //i have my error}

var responseInterceptor=new SingleCallInterceptor({success:successfn,error:errorfn});

        $http({

        url: "www.itsdirtysolutioniknow.it,

        method: "GET",

        dataType: "JSONP",

      }).then(responseInterceptor.receive,responseInterceptor.receive);
dnocode
  • 1,928
  • 1
  • 18
  • 21
0

By default angular sends and receives application/json headers. You can get this on the HTTP response header like :

services.config(['$httpProvider',function($httpProvider) {
    $httpProvider.interceptors.push('myHttpInterceptor');
}]);

services.factory("userPurchased", function ($resource) {
    return $resource("/api/user/purchases/:action/:item", 
        {}, 
        {
            'list': {method: 'GET', params: {action: 'list'}, isArray: false},
            'save': {method: 'PUT', params: {item: '@item'}},
            'remove': {method: 'DELETE', params: {item: '@item'}},
        }
    );
});

services.factory('myHttpInterceptor', function($q,$rootScope) {
    // $rootScope.showSpinner = false;
    return {

      response: function(response) {
        // use this line to if you are receiving json, else use xml or any other type
        var isJson = response.config.headers.Accept.indexOf('json')>-1;
        $rootScope.showSpinner = false;
        // do something on success
        console.log('success');
        console.log('status', response.status);
        //return response;
        return response || $q.when(response);
      },

     responseError: function(response) {
        // use this line to if you are receiving json, else use xml or any other type
        var isJson = response.config.headers.Accept.indexOf('json')>-1;
        // do something on error
        $rootScope.showSpinner = true;
        console.log('failure');
        console.log('status', response.status)
        //return response;
        return $q.reject(response);
      }
    };
  });
Yacine MEDDAH
  • 1,211
  • 13
  • 17
0

I just came across an issue where googleapis also uses an Authorization header, and was throwing a 401 response because the JWT I use on my server wasn't valid for their server (obviously), and my code was set to automatically remove my token and redirect the person to the login page. (It wasn't written super well, since ANY 401 response would log my user out).

I just came up with this solution in my request method in the interceptor, which I think works pretty well:

.service('authInterceptor', ["$q", "$location", "tokenService", function($q, $location, tokenService){
    this.request = function(config) {
//        console.log($location.host());
        var token = tokenService.getToken();
        if(token && config.url.indexOf($location.host()) > -1) {
            config.headers = config.headers || {};
            config.headers.Authorization = "Bearer " + token
        }
        return config
    }

    this.responseError = function(response) {
//        console.log(response.config.url)
        if (response.status === 401) {
            tokenService.removeToken();
            $location.path('/login')
        }
        return $q.reject(response);
    }
}])

The request method checks if I have a token in local storage AND if the request url is being made to the same host (which I get from $location.host()) as the one my page is being served up on. This works for localhost as well as whatever URL I end up deploying my site on.

I haven't done much testing with this, so if anyone finds a flaw in this please let me know :)

bobbyz
  • 4,946
  • 3
  • 31
  • 42
0

I know it is an old question but I wanted to provide a solution if you have pushed multiple $http Interceptors and want them to continue working, return your response so the Interceptor chain continues:

    module.factory('resourceInterceptor', ['$q', function($q) {
        return {
            response: function(response) {
                // do your conditional logic here
                if (...) {
                    return $q.resolve(response);
                }
            },
            responseError: function(response) {
                // do your conditional logic here   
                if (...) {
                    return $q.reject(response);
                }
            }
        };
    }]);