15

How do I add interceptors to a $resource call?

Let's say I have a resource factory called Users, like so;

app.factory('Users', ['$resource', 'resourceInterceptor',
  function ($resource, resourceInterceptor) {
    return $resource(
      'users/:user_id',
      {
        user_id: '@id'
      },
      {
        query: {
          method: 'GET', // Not changing the default method, just adding an interceptor
          interceptor: resourceInterceptor // Is there any better way to do this.. like globally?
        },
        save: {
          method: 'POST', // Same here
          interceptor: resourceInterceptor // Again...
        },
        ..., // And so on
      }
    );
  }]);

and my resourceInterceptor service looks like;

app.factory('resourceInterceptor', ['$rootScope',
  function ($rootScope) {
    return {
      request: function () {
        // This function isn't executed at all?
        $rootScope.loading = true;
      },
      response: function () {
        $rootScope.loading = false;
      },
      responseError: function () {
        $rootScope.loading = false;
      }
    };
  }]);

First of all, the request intercept function is never executed, why not?

Secondly, having to hardcode the interceptor to existing $resource methods is very tedious , is there a way to easier assign interceptors to specific $resource calls, or maybe even assign an interceptor to all $resource calls?

1
  • Hello @Unidan. One year later ... do you have an answer to your question ? Commented Dec 29, 2015 at 15:42

3 Answers 3

16

To use an interceptor in a resource you should:

1 - Make an httpInterceptor with you request, response, responseError:

app.factory('myInterceptor', function () {
    //Code
    //return { request:...,
});

2 - Config this Interceptor in your app:

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

Right now as you have config your httpProvider to has an interceptor wherever you inject $http you will use this provider so... you will excute your request, response and responseError funciton.

3 - Using it in a resource. As $resource use $http and you have config a httpProvider globaly you will call your interceptors' func when you use your resource.

Second question: You can not set an interceptor to a concrete $http object, they (interceptors) are set globally.

(Even if you set the interceptor before your module definition and then you remove it, you can not know the execution order)

What you can do if you do not want to override the interceptor property in each $resource action (as you write in your question) you can improve your interceptor.

app.factory('userLoadingInterceptor', function () {
    //Code
    return {
        request: function(){
            //Check if your are working with a url related with users
            // and if so do things...
        }
});
Sign up to request clarification or add additional context in comments.

2 Comments

Yeah but is there a way to specifically identify which requests are called through a $resource object, and which is just plain $http.
As $resource use $http and as you are defining an interceptor in the $httpProvider. Your interceptor only do things at $http level. I am going to edit my answer
0

From the docs:

The interceptor object has two optional methods - response and responseError

I don't know what you want to achieve but generic HTTP interceptors might be an alternative.

3 Comments

Afaik, the $resource service uses $http. The docs for $http interceptors (docs.angularjs.org/api/ng/service/$http#!) has a request field.
@WillB Do you really think the angular docs are wrong? $resource uses $http, but the interceptors used by $resource have no relation whatsoever to the interceptors of the $http service. Another alternative might be a decorator for $resource.
No, of course I don't think the docs are wrong. I just can't find the docs for $resource interceptors, so I assumed it was the same as $http interceptors. (Found it now on my laptop, was on mobile before). Well that sucks. What I want to achieve is a loading bar that is only shown when using a resource. I'll take a look at decorators.
0

A generic HTTP Interceptor should do what you want. You can find a sample here: Handle HTTP 302 response from proxy in angularjs.

2 Comments

Adding an interceptor to the $http service will also trigger when angular loads static assets behind the scenes, which is not desired. Im sure there are ways to detect what kind of request it is, but it feels wrong. I guess I can just make a service that is injected to my controllers and deal with it there.
You should be able to configure the interceptor to not handle the error based upon the URL.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.