I'm using Ember-Data 1.0.0.Beta-9 and Ember 1.7 to consume a REST API via DreamFactory's REST Platform. (http://www.dreamfactory.com).
I've had to extend the RESTAdapter in order to use DF and I've been able to implement GET and POST requests with no problems. I am now trying to implement model.save() (PUT) requests and am having a serious hiccup.
Calling model.save() sends the PUT request with the correct data to my API endpoint and I get a 200 OK response with a JSON response of { "id": "1" } which is what is supposed to happen. However when I try to access the updated record all of the properties are empty except for ID and the record on the server is not updated. I can take the same JSON string passed in the request, paste it into the DreamFactory Swagger API Docs and it works no problem - response is good and the record is updated on the DB.
I've created a JSBin to show all of the code at http://emberjs.jsbin.com/nagoga/1/edit
Unfortunately I can't have a live example as the servers in question are locked down to only accept requests from our company's public IP range.
DreamFactory provides a live demo of the API in question at
https://dsp-sandman1.cloud.dreamfactory.com/swagger/#!/db/replaceRecordsByIds
OK in the end I discovered that you can customize the DreamFactory response by adding a ?fields=* param to the end of the PUT request. I monkey-patched that into my updateRecord method using the following:
updateRecord: function(store, type, record) {
var data = {};
var serializer = store.serializerFor(type.typeKey);
serializer.serializeIntoHash(data, type, record);
var adapter = this;
return new Ember.RSVP.Promise(function(resolve, reject) {
// hack to make DSP send back the full object
adapter.ajax(adapter.buildURL(type.typeKey) + '?fields=*', "PUT", { data: data }).then(function(json){
// if the request is a success we'll return the same data we passed in
resolve(json);
}, function(reason){
reject(reason.responseJSON);
});
});
}
And poof we haz updates!
DreamFactory has support for tacking several params onto the end of the requests to fully customize the response - at some point I will look to implement this correctly but for the time being I can move forward with my project. Yay!
EmberData is interpreting the response from the server as an empty object with an id of "1" an no other properties in it. You need to return the entire new object back from the server with the changes reflected.
Related
I built an API service that will process REST requests and use them to perform CRUD operations on a MongoDB instance. This application is standalone (by design) and should be a passthrough for anything that calls it. My other application that I built in Angular is calling this API to interact with my MongoDB instance. I have been trying to construct my JSON payload from a form, which works fine. I get something like:
{ "_id":"111111111", "name":"herp", "address":"derp", "city":"foo", "state":"bar", "zip":"11111", "phone":"111-222-3333"}
I am then trying to take that JSON and send it along to the service, but something is getting lost in translation once the service gets a hold of it and my variable name that contains the JSON object is being turned into an actual key in the request, with the JSON as its value. I am calling the service like this:
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json', 'Cache-Control': 'no-cache' })
};
updateStuff(update){
console.log("Sending: " + JSON.stringify(update) + " for update");
return this.http.put('http://localhost:3000/api/test/_update', {dbName:"testDb",collection:"testing",update}, httpOptions);
}
Which logs:
Sending: {"name":"blah","address":"111 Anystreet","city":"MyCity","state":"NY","zip":"11111","phone":"555-111-2222","_id":"5ba914df13236f7a6ea3e233"} for update
So I know that right before the call is made, the data is fine. However, on the other side, it sees the following when it gets the data:
Received request: {"dbName":"testDb","collection":"testing","update":{"name":"blah","address":"111 Anystreet","city":"MyCity","state":"NY","zip":"11111","phone":"555-111-2222","_id":"5ba914df13236f7a6ea3e233"}}
instead of what I intended, which is below:
{"dbName":"testDb","collection":"testing","name":"blah","address":"111 Anystreet","city":"MyCity","state":"NY","zip":"11111","phone":"555-111-2222","_id":"5ba914df13236f7a6ea3e233"}
How do I tell the HTTP request to send the data itself rather than constructing a new key with the name "update" and sticking the payload in there as its value? I tried JSON.stringify, but that ends up sending the same thing, but with a bunch of backslashes in front of all the parenthesis. It still sends it all in a key with the name "update" as well. Any help would be greatly appreciated.
Your problem is here:
{dbName:"testDb",collection:"testing",update}
The statement above is shorthand for this:
{dbName:"testDb",collection:"testing",update:update}
What you're looking to do is this:
{dbName:"testDb",collection:"testing",...update}
Which is shorthand for this:
const data = {dbName:"testDb",collection:"testing"};
for (let key in update) {
if (update.hasOwnProperty(key)) {
data[key] = update[key];
}
}
I've read other posts that have similar 404 errors, my problem is that I can correctly query the JSON data, but can't save without getting this error.
I'm using Angular's $resource to interact with a JSON endpoint. I have the resource object returning from a factory as follows:
app.factory('Product', function($resource) {
return $resource('api/products.json', { id: '#id' });
});
My JSON is valid and I can successfully use resource's query() method to return the objects inside of my directive, like this:
var item = Product.query().$promise.then(function(promise) {
console.log(promise) // successfully returns JSON objects
});
However, when I try to save an item that I've updated, using the save() method, I get a 404 Not Found error.
This is the error that I get:
http://localhost:3000/api/products.json/12-34 404 (Not Found)
I know that my file path is correct, because I can return the items to update the view. Why am I getting this error and how can I save an item?
Here is my data structure:
[
{
"id": "12-34",
"name": "Greece",
"path": "/images/athens.png",
"description": ""
},
...
]
By default the $save method use the POST verb, you will need to figure out which HTTP verbs are accepted by your server en order to make an update, most modern api servers accept PATCH or PUT requests for updating data rather than POST.
Then configure your $resource instance to use the proper verb like this :
app.factory('Product', function($resource) {
return $resource('api/products.json', { id: '#id' }, {'update': { method:'PUT' }});
});
check $resource docs for more info.
NOTE: $resource is meant to connect a frontend with a backend server supporting RESTful protocol, unless you are using one to receive data & save it into a file rather than a db.
Otherwise if you are only working with frontend solution where you need to implement $resource and have no server for the moment, then use a fake one, there is many great solutions out there like deployd.
You probably don't implement POST method for urls like /api/products.json/12-34. POST method is requested from angular for saving a new resource. So you need to update your server side application to support it and do the actual saving.
app.factory('Product', function($resource) {
return $resource('api/products.json/:id', { id: '#id' });
});
Try adding "/:id" at the end of the URL string.
I have the following situation:
I use ngResource to save some data to the mysql database and after the successfull save() I want to log the json response the server sends to me:
Document.save({}, postData, function(response){
console.log(response);
});
This does not result in a simple response, but in something like an object with its own methods. I want some smple output like the response.data after an $http.$get:
{
"docClass":"testets",
"colCount":1,
"columns":null,
"groupid":7,
"id":19,
"lang":"de",
"title":"test",
"version":1409849088,
"workflow":"12234"
}
Greets
Check out this answer
Promise on AngularJS resource save action
So I think in your case you need to do
var document = new Document(postData);
document.$save()
.then(function(res){});
But also from the link I provided
This may very well means that your call to $save would return empty reference. Also then is not available on Resource api before Angular 1.2 as resources are not promise based.
I have a simple Backbone.js/Bootstrap front end in HTML5 with a Node.js/Restify backend. I am setting cookies in a header response from the server as below:
res.setHeader("Set-Cookie", ["token=ninja", "language=javascript"]);
On the client side, I am making a REST call as
var response = this.model.fetch().success(function(data){
//success
}).error(function(data){
//error
}).complete(function(data){
//complete
});
that callsback a parse method in the model.
How can I read the cookie value in the model?
Include Cookie.js.
You can then reference individual cookies like this:
var token = Cookie.get('token')
# token == 'ninja'
Here is what I figured out. My application has two components - the HTML/js from one domain that talks to a REST sevice on another domain (and therefore is cross-domain.) Because the cookie is set from REST, it appears is not readable across domains. So the web page will not store the cookie even though the server is sending it. One alternative is to use local cookies or use the technique illustrated by http://backbonetutorials.com/cross-domain-sessions/.
Assuming you are using jQuery with Backbone, you can get the headers by defining the parse function in your model by calling getAllResponseHeaders or getResponseHeader:
var model = Backbone.Model.extend({
// the rest of your model
parse: function(resp, xhr) {
var allHeaders = xhr. getAllResponseHeaders();
var cookieHeader = xhr. getResponseHeader("Set-Cookie");
// do something with the headers
return resp;
}
});
Here is a typical JQGrid JSON response:
{
"page":1,
"records":537,
"rows":[..],
"rowCount":10,
"total":54
}
Along with this, I want to send additional custom data. For example, I'd like to send the database time of the last search so that I can lazy-reload my grid whenever changes have occurred since then. Here is how I would like to send that data:
{
//Custom name-value pairs:
"nameValues":{"lastSearchTime":"2011/09/01:14:14:56"},
//Normal JSON data:
"page":1,
"records":537,
"rows":[..],
"rowCount":10,
"total":54
}
The problem is that JQGrid swallows up the JSON response rather than forwarding it to the gridComplete method. In other words, params is undefined in the following function:
function myGridComplete (params){
//params is undefined!
var JSONResponse = ?;//I need your help here!!!
globalGridVariables.lastSearchTime = JSONResponse.nameValues.lastSearchTime;
//Rest of grid complete method
..
}
Please let me know if there is a way to get access to the JSON response object in the gridComplete method, or if there is another supported way to add custom data to a JSON response.
Thanks much!
Note: I don't want to send this as a hidden column, because that would be inefficient.
You can use loadComplete instead of gridComplete. The loadComplete event has one parameter (for example data) which represent the full data from the server response inclusive all of your extensions.
Alternative you can rename the nameValues to userdata and use $('#list').jqGrid('getGridParam', 'userData') to get the value. See here for more information.
Moreover you can consider to use more HTTP caching (see here and here) for the aims which you described in your question.
You can use beforeProcessing that has the deserialized response and gets active before gridComplete and loadComplete.
For example:
beforeProcessing: function (data, status, xhr) {
myArray = data.rows;
}
And just to make it more clearer from the documentation:
Below is the execution order of the events when a ajax request is made
beforeRequest
loadBeforeSend
serializeGridData
loadError
beforeProcessing
gridComplete
loadComplete