Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EmberJS embedded items in payload JSONAPI

Ember      : 1.13.3
Ember Data : 1.13.5
jQuery     : 1.11.3

I am trying to send a JSON payload using ember-data from my EmberJS client to my server. I want to send the entire object graph to the server on saving the project, as I don't want to send multiple requests. I wouldn't mind sending multiple requests, but I am worried about what happens if one of the requests fails in the middle and the data on the server will not be correct.

I wanted to use JSONAPI (http://jsonapi.org/format/#document-compound-documents) as that is becoming the default adapter in Ember. Also, there is a few C# libraries that handle this format, so I thought it would be quite straightforward. However, after reading the spec, it seems that I cannot embed objects if they do not have an id. EmberJS also does not attach the child objects to the JSON either even though I have specified { async: false, embedded: 'always' }) on the DS.attr.

My question is: If an application is used in such a way that an object graph is created on the client side, how do you use JSONAPI format to send the entire object graph to the server? Do I have to generate ids on the client side to satisfy the JSONAPI standard? Then once they get to the server just ignore them so they get saved with an id generated by the ORM?

Here is my labelGroup model:

import DS from 'ember-data';

export default DS.Model.extend({
  name: DS.attr('string'),
  labels: DS.hasMany('label-model', { async: false, embedded: 'always' })
});

Here is my project model:

import DS from 'ember-data';

export default DS.Model.extend(DS.EmbeddedRecordsMixin, {
  name: DS.attr('string'),
  labelGroups: DS.hasMany('labelGroup', { async: false, embedded: 'always'})

});

Here is the POST that I get after doing a save() on the project:

{
  "data":{
    "attributes":{"name":"Project"},
    "relationships":{
      "label-groups":{
        "data":[
         {"type":"label-groups","id":null},
         {"type":"label-groups","id":null},
         {"type":"label-groups","id":null},
         {"type":"label-groups","id":null},
         {"type":"label-groups","id":null},
         {"type":"label-groups","id":null},
         {"type":"label-groups","id":null}
       ]
     }
   },
   "type":"label-projects"
  }
}

UPDATE: I tried using https://www.npmjs.com/package/ember-cli-uuid to generate client side ids which it has. However the data getting output does not include the extra objects, only a reference to their ids. I expected to see an "included" property as specified here:http://jsonapi.org/format/#document-compound-documents, but it is not there.

{
  "data":{
    "id":"7b4544ee-91cd-493d-8b10-52040e68c283",
    "attributes":{"name":"Project"},
  "relationships":{
    "label-groups":{
      "data":[
       {"type":"label-groups","id":"08115273-e82a-4d46-93ea-232ce071fb78"},
       {"type":"label-groups","id":"9ca94fe9-8077-411e-98d2-1694c6fecce4"},
       {"type":"label-groups","id":"d629f1e8-7962-404d-8034-38229ab21f77"},
       {"type":"label-groups","id":"c6bda655-5489-4760-847b-bf02239bb2c5"},
       {"type":"label-groups","id":"f6fef249-2d1d-43f0-ba64-24b7ff8b5637"},
       {"type":"label-groups","id":"a7db25bf-52c8-477b-83e4-64e7c76b072e"},
       {"type":"label-groups","id":"f3b5fbb3-261a-4b3d-b481-b9352f8ce2d6"}
      ]
    }
  },
  "type":"label-projects"
  }
}
like image 451
Asagohan Avatar asked Sep 02 '15 23:09

Asagohan


1 Answers

Ember-data has no support for what you want at the moment. So ember-data will not save your relationships data in a save payload.

But its possible to do this your own by using a custom adapter and serializer. I strongly recommend you to checkout the API and then look into the source.

If you call .save() on your Model the createRecord method is called on your adapter. Here serializeIntoHash on the serializer is called to serialize the Model.

serializeIntoHash calls serialize, where serializeBelongsTo and serializeHasMany is called.

Now you can just override serializeHasMany and modify the hasMany before the line:

json[payloadKey] = hasMany;

Here you have the type and the ids as they are sent by ember-data. You could just .forEach the data on the hasMany and then fetch the store for the data and build your included array.

I hope this helps you to understand the serializer and the adapter so you can modify it to do whatever you want pretty easy. Actually this is the best part about ember-data. The structure of the adapter and the serializer, which allows easy modifications.

like image 96
Lux Avatar answered Oct 15 '22 02:10

Lux