Ember-Data and CORS


#1

From the documentation it seems that Ember-Data is claiming to support CORS out of the box:

If your JSON API runs on a different domain than the one serving your Ember app, you can change the host used to make HTTP requests.

Note that in order for this to work, you will need to be using a browser that supports CORS, and your server will need to be configured to send the correct CORS headers.

Given this comment by Pete Wagenet in this pull request, he says:

Given inconsistent browser behavior, for now I think we should just expect the user to overwrite the RESTAdapter’s ajax method. I don’t really want to add something that will only work in some browsers. If you still feel strongly about this, start a discussion on the Ember forums.

So what is the way to go? Should I overwrite the $.ajax object in the $.ajaxSend filter? Or cross my fingers and hope there is an Ember Way coming soon?


#2

Howdy Andrew.

Ember-Data has no special support for CORS, but since Ember-Data is composed of flexible primitives adding support to your application should be simple. For instance adding CORS support to a single endpoint is pretty easy:

App.ThingAdapter = DS.RESTAdapter.extend({
  findAll: function(store, type, id) {
    return this.ajax("https://cors-test.appspot.com/test", "GET", {
      // CORS
      crossDomain: true,
      xhrFields: {withCredentials: true}
    }).then(function(json) {
      // Massage this demo API endpoint to look like RESTAdapter expects.
      return { things: [json] };
    });
  }
});

A fiddle: http://emberjs.jsbin.com/osULomo/2/edit?html,js,output

The ajax method called above is just a promise-returning wrapper around jQuery’s XHR. You could also add CORS and a custom host to all models:

App.ApplicationAdapter = DS.RESTAdapter.extend({
  host: 'https://otherhost.com',
  ajax: function(url, method, hash) {
    hash.crossDomain = true;
    hash.xhrFields = {withCredentials: true};
    return this._super(url, method, hash);
  }
});

Again, a demo: http://emberjs.jsbin.com/osULomo/3/edit?html,js,output

Ember-Data is currently best viewed (imo, and hopefully not forever), as a great set of primitives. All the extension points for something like CORS are present, if a little under-documented.

Of course, I personally use an ajaxPrefilter call to handle this in several apps which is yet another way to tackle CORS. There really are plenty of options, and just because you use Ember-Data doesn’t mean you need to ignore jQuery APIs.


#3

I’d like to mention https://github.com/jpillora/xdomain if anybody doesn’t know about it yet. For reasons explained in its introduction, it’s often a more elegant solution.

I spent many, many hours to get CORS working in Ember Data perfectly (1.5 years ago and again 2 months ago) and I was running into problems with some advanced requests requiring inelegant fixes.


#4

@mixonic You saved me so much time. (I wish I had found this 4 hours ago :)).

One modification I had to make was to handle the case where hash is undefined.

 ajax: function(url, method, hash) {
    hash = hash || {}; // hash may be undefined
    hash.crossDomain = true;
    hash.xhrFields = {withCredentials: true};
    return this._super(url, method, hash);
  }

Thanks again!