Metadata passthrough for ngResource queries
When using the $resource factory to access RESTful APIs it might by necessary to consume resources, that do not return the data as expected by $resource, this is often the case for server-side pagination, where the result is usually not a plain array but an object that contains the result as well as additional metadata such as a total count, page size, etc...
This fiddle demonstrates how to circumvent the limitations of $resource as of version 1.2.12 to enable you to consume data with any structure and pass through any metadata while retaining all the behavior provided by $resource.
HTML
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.12/angular.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.12/angular-resource.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.12/angular-mocks.js"></script>
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.0/css/bootstrap.min.css">
<div ng-app="w2MetadataDemo">
<div ng-controller="demoController">
<div class="panel panel-primary">
<div class="panel-heading">Displaying {{items.length}} of {{items.$metadata.total}} items</div>
<ul class="list-group">
<li class="list-group-item" ng-repeat="item in items">{{item.text}}</li>
</ul>
</div>
</div>
</div>
JavaScript
angular.module('w2MetadataDemo', ['ngResource'])
.service('Item', function ($resource) {
return $resource('/api/resource/', {}, {
list: {
method: 'GET',
isArray: true,
// The response is not a JSON array as expected by $resource but rather a
// JSON object that contains the actual result with additional metadata.
// It is therefore necessary to extract the payload before it can be
// processed by the resource.
transformResponse: function (data) {
var wrappedResult = angular.fromJson(data);
wrappedResult.data.$metadata = wrappedResult.metadata;
return wrappedResult.data;
},
// The response ist not a JSON array as expected by $resource but rather a
// JSON object that contains the actual result with additional metadata.
// It is therefore necessary to extract the payload before it can be
// processed by the resource.
// The array returned by transformResponse is not passed directly to the
// application logic, $resource only copies its contents. Due to this we
// cannot directly access the added metadata. But fortunately for us
// we can register a response interceptor in addition to transformResponse.
// Inside the interceptor we can access the array of instances that is
// returned by the query and the original data we parsed in
// transformResponse, so that we can add the metadata.
//
// CAVEAT: This depends on the fact that the actual result is exposed as
// response.resource which might change in future versions
interceptor: {
response: function (response) {
response.resource.$metadata = response.data.$metadata;
return response.resource;
}
...