Частичные обновления (aka PATCH) с использованием службы на основе $ресурсов?

Мы создаем веб-приложение с использованием Django/TastyPie в качестве внутреннего поставщика услуг REST и создаем фронт-интерфейс на основе AngularJS, используя множество сервисов, основанных на ресурсах, для объектов CRUD на сервере. До сих пор все отлично работает!

Но мы хотели бы уменьшить объем данных, которые мы отправляем, когда хотим обновить только одно или два измененных поля объекта.

TastyPie поддерживает это с помощью метода HTTP PATCH. Мы определили метод .diff() для наших объектов, поэтому мы можем определить, какие поля мы хотим отправить при обновлении. Я просто не могу найти документацию о том, как определить/реализовать метод объекта экземпляра, возвращаемого $resource, чтобы делать то, что мы хотим.

Что мы хотим сделать, это добавить еще один метод к экземплярам объекта (как описано в документации Angular.js здесь), например myobject. $partialupdate (), который:

  • Вызовите нашу функцию .diff(), чтобы определить, какие поля отправлять, а затем
  • Используйте запрос HTTP PATCH для отправки только этих полей на сервер.

До сих пор я не могу найти какую-либо документацию (или другие сообщения SO), описывающие, как это сделать, но по-настоящему оценил бы любые предложения, которые могут быть у кого-либо.

спасибо.

Ответ 1

Мы реализовали $patch с помощью ngResource, но это немного связано (мы используем Django Rest Framework на стороне сервера). Для вашего компонента diff я оставлю вашу собственную реализацию. Мы используем первоклассный кеш для отслеживания изменений ресурсов, поэтому я могу опросить данный объект и посмотреть, что изменилось (если оно есть).

Я использую метод underscore _.pick(), чтобы вытащить известные поля, чтобы сохранить существующий экземпляр, создать копию (вместе с известным первичным ключом) и сохранить ее с помощью $patch.

Мы также используем некоторые служебные классы для расширения встроенных ресурсов.

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
]

Здесь классы утилиты для улучшения ресурсов.

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
]

Наконец, мы можем улучшить наш ресурс

include TheResource, PartUpdateMixin(TheResource)
resourceInstance = TheResource.get(id: 1234)
# Later...
updatedFields = getChangedFields(resourceInstance)
resourceInstance.partial_update(updatedFields...)

Ответ 2

Я бы предложил использовать

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

где

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: не уверен в памяти, является ли data ссылкой на ваш ресурс его копии, поэтому вам может понадобиться создать копию data, прежде чем удалять поля

Кроме того, вместо return data вам может понадобиться return JSON.stringify(data).


Source (найдите "transformRequest" на страница документации)

Ответ 3

Я предлагаю использовать Restangular через ngResource. Команда angular продолжает улучшать ngResource с каждой версией, но Restangular все еще делает намного больше, включая разрешения таких действий, как PATCH, что ngResource этого не делает. Вот большой вопрос SO, сравнивающий два В чем преимущество использования Restangular над ngResource?