2

I have two REST APIs I need to use: One from Mongolab for development purposes and one from the actual API that is not accessible at the moment. The problem is that the ID is handled a bit differently in these and the object structure differs. Mongo uses the object._id.$oid notation and the actual API object.ID notation. The Mongolab resource is:

app.factory('Items', function ($resource) {
  var items = $resource('https://api.mongolab.com/api/1/databases/x/collections/items/:id',
    {
      apiKey:'x',
      id:'@_id.$oid'
    }
  });
  return items;
});

And the query call (currently using):

$scope.items = Items.query({}, function () {
  if (API == 'Mongo') {
    angular.forEach($scope.items, function(item) {
      item.ID = item._id.$oid;
    });
  };
});

I want to be able to easily switch the different APIs without modifying the code in every query call or link (I have dozens of calls and links with resource IDs). So I want to move the API == 'Mongo' check to upper level: I tried to use the forEach ID altering directly in the factory where I create the Items resource but it doesn't work that way. How can I modify the results directly before the results are populated through query ?

Or should I just create different branches for different APIs?

Pekka
  • 959
  • 2
  • 12
  • 22

1 Answers1

2

I think you can just add two distinct factories, and query the one you need depending on the value of "API" variable.

app.factory('ItemsApi', function ($resource) {
  var items = $resource('https://api.mongolab.com/api/1/databases/x/collections/items/:id',
    {
      apiKOey:'x',
      id:'@_id.$oid'
    }
  });
  return items;
});
app.factory('ItemsMongo', function ($resource) {
      var items = $resource('https://api.mongolab.com/api/1/databases/x/collections/items/:id',
      {
        apiKey:'x',
        id:'@id'
      }
    });
    return items;
 });

Then in the controller (instead of in the resource factory) you could use:

if (API == 'Mongo') 
  $scope.items = ItemsApi.query();
else
  $scope.items = ItemsMongo.query();

UPDATE:

If this is what you currently have, then you may want to consider adding an additional property to each element in the returned array. You can do this by means of overriding the default factory query() method and then iterating over each element adding a duplicate ID field. Check this out:

$resource('https://../:id',{id: '@id'}, {
 query: { 
   isArray: true,
   method: 'GET',
   params: {},
   transformResponse: function (data) {
     var wrapped = angular.fromJson(data); 
     angular.forEach(wrapped, function(item) {
       --do something to wrapped items -- 
     });
     return wrapped;
 }
 } 

transformResponse and angular.forEach should do the trick

Pekka
  • 959
  • 2
  • 12
  • 22
Alex
  • 459
  • 4
  • 16
  • Yes, this is how it is currently done, but the problem is that you have to change all the template links too and other handling and it gets complicated. For example, ui-router transfers stateParams through link `item_detail({ itemID : item.ID })`. I'm trying to look simple way to change the basic object structure before handling it in the application. – Pekka May 05 '15 at 08:01
  • 1
    Okay then I think you could override the default _$query()_ method in $resource factory and simply add a **itemID** property to each item returned. You could do so by adding **transformResponse** to the method. An example: `$resource('https://../:id',{id: '@id'}, { query: { isArray: true, method: 'GET', params: {}, transformResponse: function (data) { return data } }` Check this out for more: http://stackoverflow.com/questions/17134401/angular-extending-resource-subobject-with-custom-methods – Alex May 05 '15 at 08:20
  • 1
    In fact you can iterate over each item and transform it to your liking like in the below example: `transformResponse: function(data, header) { var wrapped = angular.fromJson(data); angular.forEach(wrapped.items, function(item, idx) { wrapped.items[idx] = new Post(item); }); return wrapped; }`. source:http://stackoverflow.com/questions/17134401/angular-extending-resource-subobject-with-custom-methods – Alex May 05 '15 at 08:26
  • The **transformResponse** iteration with `angular.forEach` did the trick! – Pekka May 05 '15 at 10:22
  • Updated the original answer so you can mark it as correct for anyone with similar question in the future – Alex May 05 '15 at 10:37