Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Backbone Models - change URL query params depending on REST action

Inside a Backbone model, we have the url and urlRoot attributes:

           url: function(){

               return '/jobs'
            },


            urlRoot: function () {

                return '/jobs'
            },

however I want to add params or query params to the url, depending on what type of request it is GET, POST, PUT, DELETE, etc.

So I want to do something like this:

     url: function(type, opts){ //type and opts arguments are not available in Backbone, I just made them up for this example

          var url = '/jobs';

           switch (type) {
              case 'GET':
                break;
              case 'POST':
                break;
              case 'PUT':
                url = url + '?optimisticDelete=' + opts.optimisticDelete;
                break;
              case 'DELETE':
                url = url + '?upsert=' + opts.upsert;
                break;

               default:
                 throw new Error('no match');
                }

          return url;
    },

is there a good way to accomplish something like this?

like image 492
Alexander Mills Avatar asked Aug 20 '15 22:08

Alexander Mills


Video Answer


2 Answers

By default, Backbone models and collections delegate to the Backbone.sync function to interact with the server. That's the scope where you will have access to the HTTP method like in your example. You can override the sync function on a model or collection to customize this behavior. Check out the documentation and source code for Backbone.sync and for jQuery.ajax, which Backbone.sync uses.

I haven't touched Backbone or JavaScript in a while, but I would imagine it would look something like this (this is basically pseudo-code, don't expect it to work as written):

sync: function (method, model, options) {
    // method corresponds to the HTTP verb ("type" in your example)
    switch (method) {
      // ...build the correct url like in your example...
    }
    options = options || {};
    options.url = url; // tack correct url onto options object
    return Backbone.sync.apply(this, [method, model, options]);
}

It will most likely take more fiddling than this, but hopefully it gets the point across.

like image 183
trvrfrd Avatar answered Oct 19 '22 10:10

trvrfrd


I think what you have is good enough if you can specify the type when you create the url.

urlExtended: function(type, opts) {
    var url = this.url();

    switch (type) {
    case 'GET':
        break;
    case 'POST':
        break;
    case 'PUT':
        url = url + '?optimisticDelete=' + opts.optimisticDelete;
        break;
    case 'DELETE':
        url = url + '?upsert=' + opts.upsert;
        break;

    default:
        throw new Error('no match');
    }

    return url;
}

Downside is 1. need to call urlExtend() yourself when url() is needed, 2. you have to provide the 'type' argument yourslf.

If you don't like that, you could override the Backbone.sync

 Backbone.sync = function(method, model, options) {
    var type = methodMap[method];

    // Default options, unless specified.
    _.defaults(options || (options = {}), {
      emulateHTTP: Backbone.emulateHTTP,
      emulateJSON: Backbone.emulateJSON
    });

    // Default JSON-request options.
    var params = {type: type, dataType: 'json'};

    // Ensure that we have a URL.
    // if (!options.url) {
    //   params.url = _.result(model, 'url') || urlError();
    // }

      if (!options.url) {
          if(model.urlExtended) {
              // type is GET, POST...
              // options are what you passed to fetch, save, etc.. as options
              params.url = model.urlExtended(type, options);
          } else {
              params.url = _.result(model, 'url') || urlError();
          }
      }
... rest of Backbone.sync code..

You could place the above code after you load Backbone to override the sync.

like image 33
eugene Avatar answered Oct 19 '22 09:10

eugene