4
votes

I am trying to normalize data from REST API. I will not be changing the JSON response.

How do I generically munge this JSON response to pull out embedded records to make it so they are in a side-loaded format.

The response from the server looks like this:

{
  "objects": [
    {
      "active": true, 
      "admin": true, 
      "created_at": "2013-11-21T15:12:37.894390", 
      "email": "[email protected]", 
      "first_name": "Joe", 
      "id": 1, 
      "last_name": "Joeson", 
      "projects": [
        {
          "created_at": "2013-11-21T15:13:13.150572", 
          "id": 1, 
          "name": "Super awesome project", 
          "updated_at": "2013-11-21T15:13:13.150606", 
          "user_id": 1
        }
      ], 
      "updated_at": "2013-12-06T19:50:17.035881"
    }, 
    {
      "active": true, 
      "admin": false, 
      "created_at": "2013-11-21T17:53:17.155700", 
      "email": "[email protected]", 
      "first_name": "Craig", 
      "id": 2, 
      "last_name": "Craigson", 
      "projects": [
        {
          "created_at": "2013-11-21T17:54:05.527790", 
          "id": 2, 
          "name": "Craig's project", 
          "updated_at": "2013-11-21T17:54:05.527808", 
          "user_id": 2
        }, 
        {
          "created_at": "2013-11-21T17:54:29.557801", 
          "id": 3, 
          "name": "Future ideas", 
          "updated_at": "2013-11-21T17:54:29.557816", 
          "user_id": 2
        }
      ], 
      "updated_at": "2013-11-21T17:53:17.155717"
    }
  ]
}

I want to change JSON payload so it looks like the JSON response, ember-data is expecting:I am trying to normalize data from REST API. I will not be changing the JSON response.

How do generically munge this JSON response to pull out embedded records to make it so they are in a side-loaded format. The response from the server looks like this:

{
  "objects": [
    {
      "active": true, 
      "admin": true, 
      "created_at": "2013-11-21T15:12:37.894390", 
      "email": "[email protected]", 
      "first_name": "Joe", 
      "id": 1, 
      "last_name": "Joeson",  
      "updated_at": "2013-12-06T19:50:17.035881"
      "projects": [1]
    }, 
    {
      "active": true, 
      "admin": false, 
      "created_at": "2013-11-21T17:53:17.155700", 
      "email": "[email protected]", 
      "first_name": "Craig", 
      "id": 2, 
      "last_name": "Craigson", 
      "updated_at": "2013-11-21T17:53:17.155717"
      "projects": [2, 3]
    }
  ],
  "projects": [
    {
      "created_at": "2013-11-21T15:13:13.150572", 
      "id": 1, 
      "name": "Super awesome project", 
      "updated_at": "2013-11-21T15:13:13.150606", 
      "user_id": 1
    },
    {
      "created_at": "2013-11-21T17:54:05.527790", 
      "id": 2, 
      "name": "Craig's project", 
      "updated_at": "2013-11-21T17:54:05.527808", 
      "user_id": 2
    }, 
    {
      "created_at": "2013-11-21T17:54:29.557801", 
      "id": 3, 
      "name": "Future ideas", 
      "updated_at": "2013-11-21T17:54:29.557816", 
      "user_id": 2
    }
  ]
}

So far I am extending DS.RESTSerializer:

App.ApplicationSerializer = DS.RESTSerializer.extend({
    extractArray: function(store, type, payload, id, requestType) {
        var result = {};
        result[type.typeKey] = payload.objects;
        payload = result;

        return this._super(store, type, payload, id, requestType);
    },
    extractSingle: function(store, type, payload, id, requestType) {
        var result;
        var model = type.typeKey;

        if (payload.object) {
            result = payload.object;
        } else {
            result = payload;
        }

        var embedObjs, embedKey;

        type.eachRelationship(function(key, relationship) {
            if (relationship.kind === 'hasMany') { 
                embedKey = key;
                for (var i = 0; i < result[key].length; i++) {
                    result.key.push(result[key][i].id);
                }
                embedObjs = result[key].pop();
            }
        });

        payload[model] = result;

        if (!payload[embedKey])
            payload[embedKey] = [];

        payload[embedKey].push(embedObjs);

        return this._super(store, type, payload, id, requestType);
     }
});

My models looks like this where a project belongs to a user:

App.User = DS.Model.extend({
    active: DS.attr(), 
    admin: DS.attr(),  
    email: DS.attr(), 
    firstName: DS.attr(),  
    lastName: DS.attr(),
    password: DS.attr(),
    createdAt: DS.attr(),  
    updatedAt: DS.attr(),
    projects: DS.hasMany('project')
});
App.Project = DS.Model.extend({
    createdAt: DS.attr(), 
    name: DS.attr(), 
    updatedAt: DS.attr(),
    userId: DS.belongsTo('user')
});

I am making a mistake somewhere, but I really don't know where other than it's in extractSingle. I get the following error in the JavaScript console, "Assertion failed: Error while loading route: TypeError: Cannot call method 'toString' of undefined." My app is working without the relations.

1
Thanks for catching the missing bracket.Drew Larson
I almost have it ready...Kingpin2k

1 Answers

5
votes

Upfront, just had surgery, so I'm one handed and on a lot of oxycodone, so the code probably needs refactoring, I'll leave that up to you..

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

App.ApplicationSerializer = DS.RESTSerializer.extend({
    extractArray: function(store, type, payload, id, requestType) {
        var result = {};
        result[ Ember.String.pluralize(type.typeKey)] = payload.objects;
        payload = result;
     //   debugger;
        return this._super(store, type, payload, id, requestType);
    },
    normalizePayload: function(type, payload) {

        var result;
        var typeKey = Ember.String.pluralize(type.typeKey);

        if (payload.object) {
            result = payload.object;
        } else {
            result = payload;
        }

        var typeArr =result[typeKey];

        type.eachRelationship(function(key, relationship) {
            if (relationship.kind === 'hasMany') { 
              var arr = result[key]=[];
              for(var j=0, jlen = typeArr.length;j<jlen;j++){
                var obj = typeArr[j]; //user
                var collection = obj[key];//projects
                var ids = [];
                for (var i = 0, len=collection.length; i < len; i++) {
                  var item = collection[i];
                  arr.push(item);
                  ids.push(item.id);
                }
                obj[key]=ids;
              }
            }
        });


      return this._super(type, result);
    },
   normalizeAttributes: function(type, hash) {

    var payloadKey, key;
    if (this.keyForAttribute) {
      type.eachAttribute(function(key) {

        payloadKey = this.keyForAttribute(key);
        if (key === payloadKey) { return; }

        hash[key] = hash[payloadKey];
        delete hash[payloadKey];
      }, this);
    }
  },
  keyForAttribute: function(attr) {
    return Ember.String.decamelize(attr);
  }
});