Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angularjs - customizing $resource

I use Angular $resource for REST service. Due to the quirk in my get response, I cannot use $resource service for CRUD application.

Creating a new object work (say for Card), smilar to:

var newCard = new CreditCard();
newCard.name = "Mike Smith";
newCard.$save();

Get also works:

var card = CreditCard().get({_id:1)

But, the GET response is not the object Card itself, but other message with it (wrapper object)

{ message: ".....",
  response: Card //object
}

so when I save the instance retrieved through resource, it sends the wrapper object (with the modified Card object in response field). This probably correct, but my server expect Card object not the wrapper. Is there a way to customize $resource so that it sends the desired object. From the doc, looks like only url parameters can be changed.

$resource(url[, paramDefaults][, actions]);
like image 532
bsr Avatar asked Oct 04 '12 03:10

bsr


1 Answers

I've also had problems with the standard implementation in the $resource module. For a while I just made edits in my own local copy of the $resource file, but I found that I still was unhappy with the way they implemented REST resources. I needed more flexibility than was offered.

The standard $resource module is just a factory wrapper around $http. If you boil down the code in the $resource module you can create your own custom implementation fairly easily.

var app = angular.module('app', []);

app.factory('CreditCard', ['$http', function($http) {

    function CreditCardFactory() {

        function parseMessage(message) {
            if (message.response) {
                return message.response;
            }
        }

        function CreditCard(value) {
            angular.copy(value || {}, this);
        }

        CreditCard.$get = function(id) {
            var value = this instanceof CreditCard ? this : new CreditCard();
            $http({
                method: 'GET',
                url: '/creditcards/' + id
            }).then(function(response) {
                var data = response.data;
                if (data) {
                    angular.copy(parseMessage(data), value);
                }
            });
            return value;
        };

        CreditCard.prototype.$get = function(id) {
            CreditCard.$get.call(this, id);
        };

        return CreditCard;

    }

    return CreditCardFactory;

}]);

Then, within your controller function, inject the CreditCard factory just as you would $resource.

app.controller('CreditCardCtrl', function($scope, CreditCard) {
    $scope.creditCard = CreditCard().get(3);
});

This allows you to parse the responses of your REST actions anyway you want and also allows you to implement any actions you want. For instance: I wanted a save method on my resources that would check to see if the object had an id property before choosing to use a POST (creating a new resource when no id is available) or a PUT (updating an existing resource when a valid id is available).

This also would allow you to implement a different way of handling the JSON CSRF Vulnerability. The angular.js way is built into $http, but my company's REST API fixes this problem by wrapping JSON arrays in a dummy object. I use a custom resource like the one above to parse the dummy object out.

like image 129
brettlaforge Avatar answered Sep 19 '22 14:09

brettlaforge