avcajaraville
avcajaraville

Reputation: 9084

AngularJS: Issue with interceptors in $resource

Im having a weird behavior manipulating a response through $resource with a custom interceptor.

If I use a response interceptor like this :

angular.module( 'app.services', [] )
  .factory( 'Product', function( $resource, routesConfig ) {
      return $resource( routesConfig.catalogueEndPointg(), {}, { 
        query: { 
          method :'GET', 
          isArray : false, 
          params : { 
            page : '@currentPage'
          },
          interceptor: {
            response: function( response ) {
              // DO STUFF
              return response;
            }
          },
        } 
      });
    });

Then, from my controller :

angular.module( 'app.controllers', [])
  .controller( 'DummyController', function( $scope, Product ){
    productsPromise.$promise
      .then(
        // Success
        function ( response ) {
          console.log( response );
        });
  }); 

At this point, this is the output of the console.log( response ) :

enter image description here

On the response object, I have the data object, as expected, but I also have this resource : Resource object which also includes the response data again.

But, if I dont use a interceptor at all; Im getting the expected response :

enter image description here

I dont understand this behavior and Im concern about perform or memory issues.

Can somebody clarify this ?

PS: I need to use interceptors, because I have to modify the response from server.

Upvotes: 2

Views: 824

Answers (2)

avcajaraville
avcajaraville

Reputation: 9084

Extracted from github issue -> answered by gkalpak -> answer


The default interceptor won't add any property (the property is already there, added by ngResource for reasons I'll explain shortly). All the interceptor does is return response.resource instead of response or response.data.

How ngResource "works":

Consider the following code:

var User = $resource(...);
var userInstance = User.get({id: 1});
// Request still pending | `userInstance` is an instance of `User`
// ...
// Response arrived | `userInstance` updated with new fields (from `response.data`)

Basically, when you create a resource instance, User.get() (or whatever method you use) returns an object (or an array if isArray: true), which is an instance of User. $resource keeps a reference of this returned userInstance, so it can populate it with more properties as soon as the response arrives (basically, it will be extending userInstance with response.data).


Why does ngResource do this

This is a very handy feature of ngResource that allows you to avoid some boilerplate, when retrieving data that need to be displayed in views. Compare the following snippets:

<!-- In the view -->
Current user: {{ user.username }} &lt;{{ user.email }}&gt;

// Now, you can do this:
$scope.user = User.get({id: 1});

// You DON'T need to do this:
User.get({id: 1}).$promise.then(function (user) {
  $scope.user = user;
});

Why not directly return resource

So, why rely on a default interceptor for returning response.resource ? Why not have $resource directly return resource in the firt place (instead of attaching it to response) ? This is for allowing you to use custom interceptors that do have access to other response-related data (such as headers, status etc), while still only returning resource if you choose not to use a custom interceptor.


PS: Leaving this here in order to provide an answer. Maybe somebody will check this.

Upvotes: 2

Vinay K
Vinay K

Reputation: 5572

Don't know the reason for this behavior.

ngResource is intentionally doing this.

1 2

Upvotes: 3

Related Questions