Richard
Richard

Reputation: 4067

Ember.js REST Adapter without JSON root

The Ember.js REST Adapter expects the JSON to be returned as:

{
    "person": {
        "first_name": "Barack",
        "last_name": "Obama",
        "is_person_of_the_year": true
    }
}

But my API returns the data without a root element:

{
    "first_name": "Barack",
    "last_name": "Obama",
    "is_person_of_the_year": true
}

Is it possible to customize the REST Adapter so that it accepts my JSON data? Right now it's showing "Assertion failed: Your server returned a hash with the key 0 but you have no mapping for it"

UPDATE: Based on Sherwin Yu's answer below, this is what I came up with, seems to work so far: https://gist.github.com/richardkall/5910875

Upvotes: 7

Views: 7861

Answers (4)

wdspkr
wdspkr

Reputation: 636

The easiest way is to not use the RESTSerializer but the much simpler JSONSerializer, which does not expect a root element.

Good resources on understanding which serializer to use for a given API can be found in these two blog posts:

http://thejsguy.com/2015/12/05/which-ember-data-serializer-should-i-use.html
http://emberigniter.com/fit-any-backend-into-ember-custom-adapters-serializers/

Upvotes: 1

Ashraf Hasan
Ashraf Hasan

Reputation: 11

I solved this by extending DS.RESTSerializer. extractArray method needs to be overloaded when server response is array type.

App.PersonSerializer = DS.RESTSerializer.extend({
    extractSingle: function (store, type, payload, id) {
        var wrappedObj = {};
        wrappedObj[type.typeKey] = payload;
        return this._super(store, type, wrappedObj, id);
    }});

Upvotes: 1

Kit Sunde
Kit Sunde

Reputation: 37075

You could also normalize it into something ember would expect.

App.PersonSerializer = DS.RESTSerializer.extend({
  normalizePayload: function(type, payload) {
    var typeKey = type.typeKey;
    return {
      typeKey: payload
    }
  }
});

Upvotes: 15

Sherwin Yu
Sherwin Yu

Reputation: 3230

Yes, you can write your own custom REST adapter. Take a look at the source code in the JSONSerializer, RESTSerializer (which extends the JSONSerializer), and the REST adapter.

Basically, the you need to override the extract* methods from the JSONSerializer.

Currently, it looks something like this:

extract: function(loader, json, type, record) {
  var root = this.rootForType(type);

  this.sideload(loader, type, json, root);
  this.extractMeta(loader, type, json);

  if (json[root]) {
    if (record) { loader.updateId(record, json[root]); }
    this.extractRecordRepresentation(loader, type, json[root]);
  }
},

Notice how it checks json[root] -- you'd have to write your custom method based on your expected API response.

Another approach would be to "preprocess" the json from the API to use a root element. You could do this by finding out what methods call extract* (which passes it the json) and before it does so, modify the json to contain the root element.

Hope this helps, please let me know if it's unclear.

Upvotes: 8

Related Questions