Search code examples
angularjstastypie

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.


Solution

  • 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...)