7

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

4 Answers 4

15

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
    }
  }
});
Sign up to request clarification or add additional context in comments.

3 Comments

type isn't available anymore, just payload. emberjs.com/api/data/classes/…
This is the way to go, compared to the accepted answer as the developer doesn't have to worry about the type of the payload (Array, Single object) and doesn't have to worry about any store operations.
This is the right idea, but the code doesn’t work. The return value’s key is literally “typeKey”, not the value stored by var typeKey.
8

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.

1 Comment

Fantastic! Thank you very much! This seems to work: gist.github.com/richardkall/5910875
1

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);
    }});

Comments

1

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/

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.