Как заставить запрос POST при сохранении модели?

Мне нужно сделать POST для серверного API. Я должен отправить ключ id в тело запроса на сервер.

Я использую модель Backbone. Но, когда я делаю:

myModel.set("id", somevalue)    
myModel.save()

Запущенный сетевой запрос: URL/someValue [PUT]

Backbones выполняет не POST, а PUT и добавляет идентификатор к URL-адресу.

Так что я просто хочу передать ключ id серверу так, чтобы Backbone этого не заметил.


person Doctor    schedule 11.12.2016    source источник


Ответы (1)


Из документа Backbone:

Backbone предварительно настроен для синхронизации с RESTful API.

[...]

Обработчик sync по умолчанию сопоставляет CRUD с REST следующим образом:

  • создатьPOST /collection
  • прочитатьGET /collection[/id]
  • обновитьPUT /collection/id
  • исправлениеPATCH /collection/id
  • удалитьDELETE /collection/id

Новая запись не имеет идентификатора, поэтому, если вы укажете идентификатор модели перед ее сохранением, Backbone по умолчанию выполнит запрос PUT, поскольку считает, что вы хотите сохранить существующую запись.

Как сделать POST-запрос с идентификатором?

Выберите одно из следующих решений.

Придерживайтесь RESTful API

Очевидный вариант. Если можете, придерживайтесь стандарта.

Измените API для обработки запросов PUT/PATCH и используйте POST только при создании. Заставьте конечную точку API получать идентификатор из URL-адреса.

Рекомендации по RESTful API

Передайте параметр type1

Просто и очень хорошо работает в разовой ситуации.

Все параметры, переданные в save (или fetch), переопределяют параметры, которые функция sync определяет по умолчанию, и передаются в функцию jQuery.ajax .

источник Backbone sync

// Make the request, allowing the user to override any Ajax options.
var xhr = options.xhr = Backbone.ajax(_.extend(params, options));
var url = model.url(); // get the url before setting the `id`
model.save({ 
    id: somevalue 
}, { 
    url: url, // fix the url
    type: 'POST' // choose the HTTP verb
});

Исправить URL-адрес, который использует модель, просто, у вас также есть несколько вариантов:

  • передать параметр url (как указано выше)
  • переопределить url функцию модели

Переопределение функции url (источник) хорошо работает для ситуация, когда каждый вызов должен использовать определенный URL-адрес без добавленного к нему id по умолчанию.

var MyModel = Backbone.Model.extend({
    url: function() {
        return _.result(this, 'urlRoot') ||
            _.result(this.collection, 'url') ||
            urlError();
    }
});

Установите idAttribute на модель

Это зависит от того, что означает id, который вы пытаетесь передать в данных.

Базовая модель использует "id", имеет имя атрибута id по умолчанию. Вы можете указать другое имя, переопределив свойство idAttribute модели. Каким бы ни было имя, оно всегда автоматически становится доступным через свойство model.id.

Теперь, предполагая, что атрибут id не связан с этой моделью, а настоящее имя атрибута id этой модели похоже на UID, вы можете изменить idAttribute модели, чтобы отразить реальное имя атрибута (или это может быть даже строка, которая никогда не будет атрибутом).

var MyModel = Backbone.Model.extend({
    idAttribute: 'UID',
});

Теперь атрибут id не считается идентификатором для текущей модели, а model.isNew() вернет true, отправив запрос POST для его создания при сохранении.

Измените поведение функции sync/save

Если используемый вами API не RESTful, вы можете настроить поведение, переопределив sync функция. Это можно сделать с моделью или коллекцией или с помощью Backbone.syncфункции, которая по умолчанию используется коллекциями. и модели.

Например, если вы хотите, чтобы каждый запрос использовал POST по умолчанию для класса MyModel:

var MyModel = Backbone.Model.extend({
    sync: function(method, model, options) {
        return Backbone.sync.call(this, method, model,
            _.extend({ type: 'POST' }, options));
    }
});

Вы могли бы сделать что-то подобное только с функцией save, чтобы позволить fetch выполнять свой GET запрос как обычно.

Используйте настройку emulateHTTP2.

Если вы хотите работать с устаревшим веб-сервером, который не поддерживает стандартный подход Backbone REST/HTTP, вы можете включить Backbone.emulateHTTP. Установка этого параметра будет подделывать запросы PUT, PATCH и DELETE с HTTP POST, устанавливая заголовок X-HTTP-Method-Override с истинным методом.

[...]

Backbone.emulateHTTP = true;

model.save();  // POST to "/collection/id", with "_method=PUT" + header.

Не переопределять isNew

Эта модель уже сохранена на сервере? Если у модели еще нет id, она считается новой.

Некоторые другие ответы на этом сайте предлагают переопределить функцию isNew. Не. У этой функции есть свое предназначение, и переопределение ее для принудительного POST-запроса — это плохой хак, а не решение.

isNew используется внутри, но также может использоваться вашим кодом или другими библиотеками и плагинами Backbone.


1 Хотя я не взял это из переполнения стека, это уже был ответ Андреса Торреса Маррокина по похожему вопросу.

2 Взято из ответа Маанаса Роя.

person Emile Bergeron    schedule 11.12.2016
comment
Спасибо за ваш ответ. Для первого варианта я не могу изменить API... Я протестировал ваш второй вариант (параметр типа), и он делает почтовый запрос с ключом id в теле. Так что это хорошо, но он по-прежнему добавляет идентификатор в конец URL-адреса, поэтому, к сожалению, сервер его не примет! Что касается третьего варианта, мне трудно понять ваше решение. Является ли idAttribute компонентом/функцией магистрали или это случайное имя, которое вы выбираете? - person Doctor; 12.12.2016
comment
А для опции синхронизации, если бы я мог переопределить, разве она не переопределила бы все мои экземпляры? Потому что я не хочу нарушать мои другие запросы! Спасибо. - person Doctor; 12.12.2016
comment
@Doctor Я добавил способ изменить url для этого конкретного запроса. - person Emile Bergeron; 12.12.2016
comment
Идентификатор, который я пытаюсь передать, не идентифицирует ничего полезного, что было бы связано с моей моделью. Если бы разработчики API назвали его как-то иначе (что угодно, только не id), это не мешало бы внутреннему механизму позвоночника... - person Doctor; 12.12.2016
comment
@Doctor Если атрибут id не указывает ничего полезного для этой модели, используйте idAttribute, который служит именно этой цели. Вы можете использовать другое имя, возможно, такое, которого никогда не было в этой модели, чтобы избежать конфликта с поведением Backbone по умолчанию. - person Emile Bergeron; 12.12.2016
comment
Ваш второй вариант (вариант типа) сработал! Молодец и большое спасибо. Я проверю больше на idAttribute, так как вы думаете, что это хороший вариант для того, чего я пытаюсь достичь. Но тем не менее, вариант типа работает хорошо! Спасибо за ваше время. - person Doctor; 12.12.2016
comment
Не знаю, почему вы поощряете повторяющиеся вопросы (вопросы без каких-либо исследовательских усилий), отвечая на них, когда вы сами пометили их как дубликаты... Если вы хотите поделиться дополнительной информацией, опубликуйте свой ответ в канонических вопросах, чтобы информация была в одно и то же место, и дубликаты будут очищены ... - person T J; 13.12.2016
comment
@TJ Я только что нашел дубликат позже, когда искал дополнительную информацию, чтобы добавить к моему ответу. Сначала я нашел этот вопрос, но он не получил хороших ответов, поэтому я помечаю его как обман этого вопроса ( более новый), но затем я нашел этот другой, который имеет много голосов и разных ответов (которые я дал кредит, где после обнаружения). - person Emile Bergeron; 13.12.2016