9

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]);
3
  • Can you post a complete example on jsfiddle, or similar? In my experience, for (simple) CRUD it is not necessary to create a new object like that. What if you simply access your resource like $scope.card = Card.get({_id:1), where Card is your resource service? Also, if you tell your form what your model is, the instance gets populated automatically. Commented Oct 4, 2012 at 10:08
  • I don't think your issues is in Angular. Sounds almost like your REST implementation on the server-side has some issues. There shouldn't be a message attached to it. You might want to check that out first to make sure the body of the response is only the object you were expecting. Commented Oct 4, 2012 at 20:49
  • The server indeed is sending a wrapper around the actual object. Still, is there a way to send only the object when send back to the server (POST) Commented Oct 4, 2012 at 20:53

1 Answer 1

17

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.

Sign up to request clarification or add additional context in comments.

3 Comments

This is a great response Brett, thanks. The more I work w/ the stock $resource, the more I find the desire to write a custom wrapper atop $http.
using this method you need to implement your own save(), delete() etc methods, correct?
if i dont add CreditCard as a dependency then it does not allow to create Creditcard()

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.