I've been trying to build a CRUD application using Backbone.js and was able to retrieve a set of records into a collection using the fetch method. To perform other operations i.e. Create, Update and Delete I could always invoke Backbone.sync but I was exploring on the lines where this is performed implicitly. The fetch method sends an implicit GET request on url specified in the Collection, similarly I was looking for other methods that allow you to send POST, PUT and DELETE requests to the url. While I was building this application, I did come across a condition where Backbone was not sending a request. I was finally able to figure out as to why that happened and then it was a simple fix in my Backbone application as well as in the REST service.
Create - Add a New record to the Collection:
Adding a new record to the Collection is fairly simple. Call create method on the Collection and you would see that a POST request is sent on the URL specified in the Collection. The POST request sends the Model data in the request body in JSON format (Content-Type as application/json):
carCollectionInstance.create({BRAND: 'Hyundai', MODEL: 'i20', COLOR: 'GREY'});
Retrieve - Retrieving a set of records and adding it to the Collection:
Retrieving a set of records by sending a GET request to the server and then parsing the response using parse property is also very simple. I have explained this in my last blog post - 'Backbone.js - Parsing the response from the Server'
Delete - Deleting the models in the Collection:
This is where I had spent most of my time in figuring out as to why Backbone wouldn't send a DELETE request to the server. There were two issues here; firstly the records that the REST service returned in JSON format didn't contain the 'id' key:
{BRAND: "Ford", MODEL: "Figo", COLOR: "RED"}
{BRAND: "Honda", MODEL: "CRV", COLOR: "GREEN"}
....
I was trying to retrieve a Model from the Collection by calling collection.at(index) and then calling destroy on the Model. The destroy method indeed removed the Model from the Collection but didn't send a DELETE request to my REST service. I was frustrated to see this behavior, then I referred to the docs and understood that if a call to Model.isNew() evaluates to true then the DELETE request wouldn't be sent. Also, according to the docs a Model is considered to be new (isNew() returns true) if the Model doesn't contain an 'id' attribute. This meant that I had to change my REST service and ensure that each Model had an 'id'.
After updating the server side logic, I tried calling destroy on the retrieved Model. Even this time it didn't send a DELETE request. Soon I realized that when ColdFusion serializes any type to JSON, it changes the casing of its keys to uppercase. This is not an issue with Backbone, but in fact a bug in ColdFusion. I had to change the casing of the keys in the parse function before adding the retrieved models to Collection. The next attempt destroy the Model in the Collection and sending a DELETE request to the server worked fine. Backbone would send a DELETE request to the server by specifying the Model's 'id' as a PathParam in the url:
http://localhost:8500/rest/Car/CarService/5
The REST resource would then retrieve the 'id' value which is available as an argument.
Update - Updating the models in the Collection:
The Update mechanism is very much similar to Delete. Here a PUT request is sent to the server specifying the 'id' value in the url and also the Model data in the request body.
resultModels = carCollectionInstance.where({brand: 'Honda'});
for(var i=0; i< resultModels.length; i++) { resultModels[i].set('color','BLACK'); resultModels[i].save(); }
In this example, I'm trying to retrieve a set a records in the Collection where 'brand' is 'Honda'. This would return an array of Models which can then be updated by setting the necessary keys (model.set('key','value')) in the Model. On calling save on the Model, a PUT request would be sent to the server.
This was a good exercise for me and Backbone does a good job by implicitly calling Backbone.sync method with appropriate HTTP methods. So far I'm very impressed with what Backbone has been able to provide. I've not explored Router and Views in Backbone yet and I'm sure there will be tidbits that I'll discover while learning them. Stay tuned.
Create - Add a New record to the Collection:
Adding a new record to the Collection is fairly simple. Call create method on the Collection and you would see that a POST request is sent on the URL specified in the Collection. The POST request sends the Model data in the request body in JSON format (Content-Type as application/json):
carCollectionInstance.create({BRAND: 'Hyundai', MODEL: 'i20', COLOR: 'GREY'});
Retrieve - Retrieving a set of records and adding it to the Collection:
Retrieving a set of records by sending a GET request to the server and then parsing the response using parse property is also very simple. I have explained this in my last blog post - 'Backbone.js - Parsing the response from the Server'
Delete - Deleting the models in the Collection:
This is where I had spent most of my time in figuring out as to why Backbone wouldn't send a DELETE request to the server. There were two issues here; firstly the records that the REST service returned in JSON format didn't contain the 'id' key:
{BRAND: "Ford", MODEL: "Figo", COLOR: "RED"}
{BRAND: "Honda", MODEL: "CRV", COLOR: "GREEN"}
....
I was trying to retrieve a Model from the Collection by calling collection.at(index) and then calling destroy on the Model. The destroy method indeed removed the Model from the Collection but didn't send a DELETE request to my REST service. I was frustrated to see this behavior, then I referred to the docs and understood that if a call to Model.isNew() evaluates to true then the DELETE request wouldn't be sent. Also, according to the docs a Model is considered to be new (isNew() returns true) if the Model doesn't contain an 'id' attribute. This meant that I had to change my REST service and ensure that each Model had an 'id'.
After updating the server side logic, I tried calling destroy on the retrieved Model. Even this time it didn't send a DELETE request. Soon I realized that when ColdFusion serializes any type to JSON, it changes the casing of its keys to uppercase. This is not an issue with Backbone, but in fact a bug in ColdFusion. I had to change the casing of the keys in the parse function before adding the retrieved models to Collection. The next attempt destroy the Model in the Collection and sending a DELETE request to the server worked fine. Backbone would send a DELETE request to the server by specifying the Model's 'id' as a PathParam in the url:
http://localhost:8500/rest/Car/CarService/5
The REST resource would then retrieve the 'id' value which is available as an argument.
Update - Updating the models in the Collection:
The Update mechanism is very much similar to Delete. Here a PUT request is sent to the server specifying the 'id' value in the url and also the Model data in the request body.
resultModels = carCollectionInstance.where({brand: 'Honda'});
for(var i=0; i< resultModels.length; i++) { resultModels[i].set('color','BLACK'); resultModels[i].save(); }
In this example, I'm trying to retrieve a set a records in the Collection where 'brand' is 'Honda'. This would return an array of Models which can then be updated by setting the necessary keys (model.set('key','value')) in the Model. On calling save on the Model, a PUT request would be sent to the server.
This was a good exercise for me and Backbone does a good job by implicitly calling Backbone.sync method with appropriate HTTP methods. So far I'm very impressed with what Backbone has been able to provide. I've not explored Router and Views in Backbone yet and I'm sure there will be tidbits that I'll discover while learning them. Stay tuned.
Hi,
ReplyDeleteI have the same problem with de DELETE method.
In the following link:
https://github.com/documentcloud/backbone/issues/37
References the attribute "idAttribute".
With "idAttribute" you do not need to define an id in the Model.
Example:
var Car = Backbone.Model.extend({
idAttribute: "chasis_num",
initialize: function(){
...
...
}
})
var car1 = new Car({ chasis_num : '1234567' })
..
//add car1 to collection
..
car1.destroy()
*) In destroy of car1 will send a DELETE:
http://localhost:8500/rest/Car/CarService/1234567
Reference
http://backbonejs.org/#Model-idAttribute
I dont know if "idAttribute" fits your needs.
Thanks for the tutorials of Backbone.js!!
Martin.
Hi,
ReplyDeleteI have the same problem with de DELETE method.
In the following link:
https://github.com/documentcloud/backbone/issues/37
References the attribute "idAttribute".
With "idAttribute" you do not need to define an id in the Model.
Example:
var Car = Backbone.Model.extend({
idAttribute: "chasis_num",
initialize: function(){
...
...
}
})
var car1 = new Car({ chasis_num : '1234567' })
..
//add car1 to collection
..
car1.destroy()
*) In destroy of car1 will send a DELETE:
http://localhost:8500/rest/Car/CarService/1234567
Reference
http://backbonejs.org/#Model-idAttribute
I dont know if "idAttribute" fits your needs.
Thanks for the tutorials of Backbone.js!!
Martin.
Thanks Martin, for pointing that out. Yes, I read the documentation, perhaps I should have mentioned that in my post. In this scenario I was using a Car collection where none of the attributes would qualify as an identifier for that Model and hence I had to use the 'id' attribute.
ReplyDelete