15

I'm designing an API and also consuming it with Backbone.js. Part of the API will include search operations. For example when searching for cars, I might have something like:

http://api.mysite.com/search/cars?q=volvo

With backbone, I can see two options for consuming the results.

Option 1: A search is a Collection

var CarSearch = Backbone.Collection.extend({
    model: Car,
    initialize : function(models, options){
        this.query = options.query;
    },
    url: function(){
        return "http://api.mysite.com/search/cars?q="+this.query;
    }
});

var volvos = new CarSearch([], {query:'volvo'});
volvos.fetch();

Option 2: A search is a Model, and the results are a Collection

var CarSearchResults = Backbone.Collection.extend({
    model: Car
});

var CarSearch = Backbone.Model.extend({
    defaults: {
        "query":"",
        "carSearchResults":null
    },
    url: function(){
        return "http://api.mysite.com/search/cars?q="+this.get('query');
    },
    parse: function(resp,xhr){
        resp.carSearchResults = new CarSearchResults(resp.carSearchResults);
        return resp;
    }
});

var volvoSearch = new CarSearch();
volvoSearch.set({query:'volvo'});
volvoSearch.save();

What are the advantages / disadvantages of these options? Is there a backbone-y way of designing this?

I'm leaning towards option 2 because it seems easier to add things to the response like pagination details, or a next url. But option 2 seems messier in a couple of ways. For example, would I generate an ID on the server for the search model when it is saved? Don't think I need to get that model by ID, deleting or updating it doesn't really make sense either cause I'm not persisting it.

user1385729
  • 1,276
  • 1
  • 15
  • 19

3 Answers3

10

i dont know if its a good practice, but i use for my search the "data" option in the "fetch" method.

https://stackoverflow.com/a/6659501/1067061

Maybe it helps. Good Luck!

EDIT

This is the right way to pass query parameters in your collections url, The reference to the Docs shows how to pass the data attribute in fetch options, the data attribute is actually an object with key value pairs referring to query params and their values

Community
  • 1
  • 1
Moszeed
  • 1,037
  • 1
  • 10
  • 20
5

I would go with option one. At least imo a model should correspond to a single search result and the collection to the entire set of search results. so if you search for volvo and there are 6 items returned, each item should be a model contained within your collection.

Now this will largely depend on how you are representing a result on your server. If say for instance you have car instances then you just do the search server side using the query and return the resulting objects as json. Then you can have the returned list be the collection of car models that match the criteria. but if you are planning on returning the query results some other way then you will have to think about how the model should represent the data

dcole2929
  • 357
  • 2
  • 11
0

I would recommend using a collection, like in option 1, but without the need to define a new collection just for the search.

Take a look at my blog post about this here: http://willdemaine.ghost.io/restful-search-with-backbone/

var SearchableCollection = Backbone.Collection.extend({},{

  search: function(query, options){
    var search = $.Deferred();
    options = options || {};
    var collection = new this([], options);
    collection.url = _.result(collection, 'url') + 'search?q=' + query;
    var fetch = collection.fetch();
    fetch.done(_.bind(function(){
      Backbone.Events.trigger('search:done');
      search.resolveWith(this, [collection]);
    }, this));
    fetch.fail(function(){
      Backbone.Events.trigger('search:fail');
      search.reject();
    });
    return search.promise();
  }

});

Then you can do:

var Cars = SearchableCollection.extend({});

var findCars = Cars.search('volvo');  
findCars.done(function(cars){  
  var carsView = new CarsView({
    collection: cars
  });
  carsView.render();
});
Will Demaine
  • 1,516
  • 1
  • 11
  • 12