POST-запросы Ember.js возвращают 400 с сервера (Grape API), но успешно сохраняются в локальном хранилище
Я пытался заставить простое приложение Ember.js публиковать в Grape API в течение нескольких часов, но, похоже, я не могу заставить его работать. Я знаю, что API работает, потому что я могу публиковать в нем новые записи через документацию Swagger, и они сохраняются. Я знаю, что API и Ember работают очень хорошо, потому что я могу получить все записи с сервера и взаимодействовать с ними на странице, и я знаю, что Ember отлично работает в вакууме, потому что мои записи сохраняются в локальном хранилище.
Тем не менее, я просто не могу заставить запрос POST работать. Он всегда возвращает 400. У меня Rack-Cors настроен правильно, и у меня все настроено с ActiveModelAdapter на внешнем интерфейсе и ActiveModelSerializer на заднем конце.
Вот модель
Contact = DS.Model.extend {
firstName: DS.attr('string'),
lastName: DS.attr('string'),
email: DS.attr('string'),
title: DS.attr('string'),
createdAt: DS.attr('date'),
updatedAt: DS.attr('date')
}
и контроллер
ContactsNewController = Ember.ObjectController.extend(
actions:
save: ->
@get('model').save()
cancel: ->
true
)
Соответствующая часть API выглядит следующим образом
desc 'Post a contact'
params do
requires :first_name, type: String, desc: 'First name of contact'
requires :last_name , type: String, desc: 'Last name of the contact'
requires :email , type: String, desc: 'Email of the contact'
requires :title , type: String, desc: 'Title of the contact'
end
post do
Contact.create!(
first_name: params[:first_name],
last_name: params[:last_name],
email: params[:email],
title: params[:title]
)
end
Форма, которую я использую...
<form {{action 'save' on='submit'}}>
<h2>{{errorMessage}}</h2>
<label>First Name</label>
{{input value=firstName placeholder='First Name' type='text' autofocus=true}}
<label>Last Name</label>
{{input value=lastName placeholder='Last Name' type='text'}}
<label>Email</label>
{{input value=email placeholder='Email' type='text'}}
<label>Job Title</label>
{{input value=title placeholder='Job Title' type='text'}}
<hr>
<input type='submit' value='Save'>
</form>
И ответ я получаю...
{"error":"first_name is missing, last_name is missing, email is missing, title is missing"}
Любой берущий? Извините, я новичок в этом. Что-то не связывает, но я не знаю почему.
ОБНОВИТЬ
Больше расследований...
ИЗОБРАЖЕНИЕ: POST-запросы к API cURL (через Postman) работают просто отлично.,
Тем не менее, когда я POST из Ember, ответ сервера по-прежнему
{"error":"first_name is missing, last_name is missing, email is missing, title is missing"}
ИЗОБРАЖЕНИЕ: вывод запроса POST от Chrome Dev Tools выглядит следующим образом
Я также изменил контроллер на..., что дает вывод в журнале инструментов разработчика Chrome выше.
`import Ember from 'ember'`
ContactsNewController = Ember.ObjectController.extend(
actions:
createContact: ->
firstName = @get('firstName')
lastName = @get('lastName')
email = @get('email')
title = @get('title')
newRecord = @store.createRecord('contact', {
firstName: firstName,
lastName: lastName,
email: email,
title: title
})
self = this
transitionToContact = (contact) ->
self.transitionToRoute('contacts.show', contact)
newRecord.save().then(transitionToContact)
)
`export default ContactsNewController`
2 ответа
Я абсолютно ничего не знаю о Ember.js, но некоторое время я создавал API с использованием Grape, поэтому думаю, что смогу вам помочь. Смотря на изображение, которое вы вложили, кажется, что Ember.js создает неправильный JSON внутри полезной нагрузки, и ваш Grape API не ожидает, что JSON сформирован таким образом. Как вы можете видеть на втором изображении, он создает JSON следующим образом:
{ contact: {...} }
Однако ваш API ожидает формат JSON, подобный следующему:
{ first_name: "" ... }
Теперь посмотрите, как вы отправляете тот же запрос через Chrome Dev Tools... вы используете опцию "form-data" для создания запроса тела, и именно поэтому в данном конкретном случае он работает. Попробуйте изменить его на "raw" и указать неверный JSON выше, и вы получите ту же ошибку, что и при использовании Ember.Js.
У меня нет конкретного решения, потому что у меня нет опыта, чтобы помочь вам с Ember.Js... но вы должны что-то изменить в своем приложении Amber.js таким образом, чтобы оно создавало запрос JSON, например:
{ first_name: "", last_name: "", email: "" }
Вместо:
{ contact: { first_name: "" ... } }
Надеюсь, это поможет вам!
ОБНОВИТЬ
Другим решением вашей проблемы является изменение вашего Grape API. В этом случае вы должны создать групповой блок внутри вашего блока params, например, так (учтите, что поля контактов теперь хранятся внутри params[:contact] Hash):
desc 'Post a contact'
params do
group :contact, type: Hash do
requires :first_name, type: String, desc: 'First name of contact'
requires :last_name , type: String, desc: 'Last name of the contact'
requires :email , type: String, desc: 'Email of the contact'
requires :title , type: String, desc: 'Title of the contact'
end
end
post do
Contact.create!(
first_name: params[:contact][:first_name],
last_name: params[:contact][:last_name],
email: params[:contact][:email],
title: params[:contact][:title]
)
end
Если вы хотите изменить способ форматирования Ember JSON, вам нужно создать собственный сериализатор и переопределить функцию serializeIntoHash. Вы можете использовать этот метод для настройки корневых ключей, сериализованных в JSON. По умолчанию REST Serializer отправляет typeKey модели, которая является верблюжьей версией имени.
Ember-cli поставляется с генератором для запуска сериализаторов. Вы можете запустить его с:
ember g serializer Contact
Из коробки сериализатор будет выглядеть так:
import DS from 'ember-data';
export default DS.RESTSerializer.extend({
});
Чтобы заставить его работать с виноградом, вы можете сделать это:
import DS from 'ember-data';
export default DS.RESTSerializer.extend({
serializeIntoHash: function(data, type, record, options) {
var properties = this.serialize(record, options);
for(var prop in properties){
if(properties.hasOwnProperty(prop)){
data[prop] = properties[prop];
}
}
}
});
Больше информации в документации.