From 4c5574b50acd3c311a72c228985d03c90918a74c Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin Date: Tue, 25 Jun 2013 13:52:24 +0100 Subject: [PATCH] fix(resource): check whether response matches action.isArray When using $resource you must setup your actions carefully based on what the server returns. If the server responds to a request with an array then you must configure the action with `isArray:true` and vice versa. The built-in `get` action defaults to `isArray:false` and the `query` action defaults to `isArray:true`, which is must be changed if the server does not do this. Before the error message was an exception inside angular.copy, which didn't explain what the real problem was. Rather than changing the way that angular.copy works, this change ensures that a better error message is provided to the programmer if they do not set up their resource actions correctly. Closes #2255, #1044 --- src/ngResource/resource.js | 4 ++++ test/ngResource/resourceSpec.js | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/ngResource/resource.js b/src/ngResource/resource.js index 827886a3cbd9..3ea7e7eec910 100644 --- a/src/ngResource/resource.js +++ b/src/ngResource/resource.js @@ -472,6 +472,10 @@ angular.module('ngResource', ['ng']). promise = value.$promise; if (data) { + if ( angular.isArray(data) != !!action.isArray ) { + return $q.reject("Error in resource configuration. Expected response to contain an " + + (action.isArray?'array':'object') + " but got an " + (angular.isArray(data)?'array':'object')); + } if (action.isArray) { value.length = 0; forEach(data, function(item) { diff --git a/test/ngResource/resourceSpec.js b/test/ngResource/resourceSpec.js index 6a709fb7bf08..6227b0819a79 100644 --- a/test/ngResource/resourceSpec.js +++ b/test/ngResource/resourceSpec.js @@ -800,6 +800,27 @@ describe("resource", function() { }); }); + it('should fail if action expects an object but response is an array', function() { + var successHandler = jasmine.createSpy('successHandler'); + var failureHandler = jasmine.createSpy('failureHandler'); + $httpBackend.expect('GET', '/Customer/123').respond({id: 'abc'}); + $resource('/Customer/123').query().$promise.then(successHandler, failureHandler); + $httpBackend.flush(); + expect(successHandler).not.toHaveBeenCalled(); + expect(failureHandler).toHaveBeenCalledWith( + 'Error in resource configuration. Expected response to contain an array but got an object'); + }); + + it('should fail if action expects an array but response is an object', function() { + var successHandler = jasmine.createSpy('successHandler'); + var failureHandler = jasmine.createSpy('failureHandler'); + $httpBackend.expect('GET', '/Customer/123').respond([1,2,3]); + $resource('/Customer/123').get().$promise.then(successHandler, failureHandler); + $httpBackend.flush(); + expect(successHandler).not.toHaveBeenCalled(); + expect(failureHandler).toHaveBeenCalledWith( + 'Error in resource configuration. Expected response to contain an object but got an array'); + }); it('should transform request/response', function() { var Person = $resource('/Person/:id', {}, {