Skip to main content

Backbone.js - Creating a RESTful CRUD application

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.

Comments

  1. Hi,

    I 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.

    ReplyDelete
  2. Hi,

    I 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.

    ReplyDelete
  3. 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

Post a Comment

Popular posts from this blog

De-obfuscating javascript code in Chrome Developer Tools

I had blogged about JavaScript debugging with Chrome Developer Tools  some time back, wherein I have explained how these developer tools can help in debugging javascript code. Today Google Chrome 12 was released and my Chrome browser was updated to this version. As with every release, there have been some improvements made on performance, usability etc,. One feature that stood out for me is the ability to De-obfuscate the javascript code. What is Minification? Minification is the process of removing unnecessary characters such as white spaces, comments, new lines from the source code. These otherwise would be added to make the code more readable. Minifying the source code helps in reducing the file size and thereby reducing the time taken to download the file. This is the reason why most of the popular javascript libraries such as jQuery are minified. A minified jQuery file is of 31 KB in size where as an uncompressed one is about 229 KB. Unfortunately, debugging minified javascript f

Adding beforeRender and afterRender functions to a Backbone View

I was working on a Backbone application that updated the DOM when a response was received from the server. In a Backbone View, the initialize method would perform some operations and then call the render method to update the view. This worked fine, however there was scenario where in I wanted to perform some tasks before and after rendering the view. This can be considered as firing an event before and after the function had completed its execution. I found a very simple way to do this with Underscore's wrap method.

On GraphQL and building an application using React Apollo

When I visualize building an application, I would think of using React and Redux on the front-end which talks to a set of RESTful services built with Node and Hapi (or Express). However, over a period of time, I've realized that this approach does not scale well when you add new features to the front-end. For example, consider a page that displays user information along with courses that a user has enrolled in. At a later point, you decide to add a section that displays popular book titles that one can view and purchase. If every entity is considered as a microservice then to get data from three different microservices would require three http  requests to be sent by the front-end app. The performance of the app would degrade with the increase in the number of http requests. I read about GraphQL and knew that it is an ideal way of building an app and I need not look forward to anything else. The GraphQL layer can be viewed as a facade which sits on top of your RESTful services o