Question

I have an API that returns one resource at a time.

As an example, say I have two related resources:

  • Topics
  • Posts

Topics hasMany Posts, and Posts belongsTo a Topic.

According to the documentation (and everything I've tried and have been reading about), Ember-Data expects the JSON out of the API to be similar to the following, where both the data for Topic and the data for Posts are provided simultaneously.

"topic": {
  "id": ...,
  "title": ...,
  "author": ...
},

"posts": [{
  "id": ...,
  "commenter": ...,
  "text": ...
}, {
  "id": ...,
  "commenter": ...,
  "text": ...
}]

As I mentioned at the start of the post, my API does not do this. It would return the Topic data in one call, and the Posts data for that Topic in a second call. Changing my API to work exactly how Ember wants it is not an option.

My question is, how can I extend/override the RESTAdapter and RESTSerializer in Ember-Data to support loading data from multiple API calls? Is this even possible?

I tried following this example, but it looks like the data here is already loaded (it tries to sideload data that is already known to the system): http://mozmonkey.com/2013/12/loading-json-with-embedded-records-into-ember-data-1-0-0-beta/

I also tried to override the extractFindAll function of the ApplicationSerializer, but can't figure out how to get the rest (no pun intended) of the application to wait for all of the relationships to load. I iterate through all of the relationships on the model, and load their data, but I don't see a way to shuttle that data back into the original payload:

extractFindAll: function (store, type, payload, id, requestType) {
  var promises = [];

  type.eachRelationship(function (key, relationship) {
    promise.push(Ember.RSVP.Promise(function (resolve, reject) {
      this.store.find(key, payloadEntry[key]);
    }));
  });

  // can't figure out how to get the relationship payloads
  // back to the original payload
  Ember.RSVP.addSettled(promises).then(function () { 
    return this._super(store, type, payload, id, requestType);
  });
}

Any help is appreciated.

Was it helpful?

Solution

That exactly describes using the async property.

Models

App.Foo = DS.Model.extend({
  bars: DS.hasMany('bar', {async: true});
})


App.Bar = DS.Model.extend({
  baz: DS.attr()
})

Adapters

App.FooAdapter = DS.RESTAdapter.extend({
  //anything custom
});

App.BarAdapter = DS.RESTAdapter.extend({
  //anything custom    
});
  • If you don't do anything custom, you should just define App.ApplicationAdapter = DS.RESTAdapter; to be a site wide adapter.

Serializer

App.FooSerializer = DS.RESTSerializer.extend({
  //anything custom
});

App.BarSerializer = DS.RESTSerializer.extend({
  //anything custom    
});
  • If you don't do anything custom, you don't need to define the rest serializers, they will use their default serializer associated with whichever adapter they're using.

Example

Important to note, I was lazy and my mock response for bars always returns the same thing regardless of any call to /bar*

http://emberjs.jsbin.com/OxIDiVU/481/edit

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top