Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Partial Updates (aka PATCH) using a $resource based service?

We're building a web application using Django/TastyPie as the back-end REST service provider, and building an AngularJS based front end, using lots of $resource based services to CRUD objects on the server. Everything is working great so far!

But, we would like to reduce the amount of data that we're shipping around when we want to update only one or two changed fields on an object.

TastyPie supports this using the HTTP PATCH method. We have defined a .diff() method on our objects, so we can determine which fields we want to send when we do an update. I just can't find any documentation on how to define/implement the method on the instance object returned by $resource to do what we want.

What we want to do is add another method to the object instances, (as described in the Angular.js documentation here) like myobject.$partialupdate() which would:

  1. Call our .diff() function to determine which fields to send, and then
  2. Use an HTTP PATCH request to send only those fields to the server.

So far, I can't find any documentation (or other SO posts) describing how to do this, but would really appreciate any suggestions that anyone might have.

thank you.

like image 959
Erik Avatar asked Oct 08 '13 21:10

Erik


2 Answers

I would suggest using

update: {
    method: 'PATCH',
    transformRequest: dropUnchangedFields
}

where

var dropUnchangedFields = function(data, headerGetter) {

    /* compute from data using your .diff method by  */
    var unchangedFields = [ 'name', 'street' ];

    /* delete unchanged fields from data using a for loop */ 
    delete data['name'] ;
    delete data['street'];

    return data;

}

PS: not sure from memory, whether data is a reference to your resource of a copy of it, so you may need to create a copy of data, before deleting fields

Also, instead of return data, you may need return JSON.stringify(data).


Source (search for "transformRequest" on the documentation page)

like image 107
iPirat Avatar answered Oct 19 '22 19:10

iPirat


We implemented $patchusing ngResource, but it's a bit involved (we use Django Rest Framework on the server-side). For your diff component, I'll leave to your own implementation. We use a pristine cache to track changes of resources, so I can poll a given object and see what (if any) has changed.

I leverage underscore's _.pick() method to pull the known fields to save off the existing instance, create a copy (along with the known primary key) and save that using $patch.

We also use some utility classes to extend the built-in resources.

app.factory 'PartUpdateMixin', ['$q', '_', ($q, _) ->

    PartUpdateMixin = (klass) ->
        partial_update: (keys...) ->
            deferred = $q.defer()
            params = _.pick(@, 'id', keys...)
            o = new klass(params)
            o.$patch(deferred.resolve, deferred.reject)
            return deferred.promise
]

Here's the utility classes to enhance the Resources.

app.factory 'extend', ->
    extend = (obj, mixins...) ->
        for mixin in mixins
            obj[name] = method for name, method of mixin
        obj

app.factory 'include', ['extend', (extend) ->
    include = (klass, mixins...) ->
        extend klass.prototype, mixins...

    return include
]

Finally, we can enhance our Resource

include TheResource, PartUpdateMixin(TheResource)
resourceInstance = TheResource.get(id: 1234)
# Later...
updatedFields = getChangedFields(resourceInstance)
resourceInstance.partial_update(updatedFields...)
like image 4
Kevin Stone Avatar answered Oct 19 '22 18:10

Kevin Stone