Full replacement on updating relationships [WHY?]


#1

Hello I’m looking at the JSON-API spec found here http://jsonapi.org/format/#crud-updating-relationships

and I’m wondering why ember data did not choose to implement the 2nd method for saving relationships. Per the spec

“Note: Since full replacement may be a very dangerous operation, a server may choose to disallow it. For example, a server may reject full replacement if it has not provided the client with the full list of associated objects, and does not want to allow deletion of records the client has not seen.”

It seems that the 2nd method for saving relationships is safer and in fact I don’t think that the first method should be allowed at all since saving full relationships brings up issues with stale data, race conditions, and incomplete paginated records. Anyone have any insight?


#2

First of all you must realize ember-data is more than an abstraction of the JSON-API. It’s a client side data store.

At this time you save models to the server, not just their relationships. Every change to a model is local until the model is saved. If you save a model and attributes and multiple relationships were changed (added and deleted) you would need one request to save the attributes, one request of each relation were something was added and another request for each relation were something was deleted.

I think the current implementation works best for most scenarios. In the future it might be made possible to just persist (save) a specific relation. Then this 2nd method might become useful. But again, changes are local until saved. Objects might have been added and deleted. Requiring two requests to the server.


#3

I don’t agree that full saving of embedded relationships works for most scenarios. In fact I think it rarely or never works for any scenario. The reason is that a client rarely sees the entire relationship. Consider a user who has a many-to-many relationship with songs (a playlist). In order to add a new song to the playlist how would you do that?

This solution is forcing us to send the entire playlist with the new addition (or deletion). What if your playlist was 100,000 records long? What if other people are allowed to add to your playlist? I can think of several hacks including to make the playlist some sort of relationship model or making a custom serializer but none of it seems right.


#4

@rickshawhobo in that case you could just add the playlist to the song and save the song!

And always remember that you usually have a reduced Entity-Relationship-Model for you API that does not match your full backend-DB.


#5

That doesn’t make any sense. A song doesn’t know anything about a playlist. Are you saying a song would have a playlist_id? A song could belong to many playlists. Also why I am “saving a song” when the state of the song hasn’t changed. Am I missing something? Can you explain “reduced Entity-Relationship-Model”?


#6

You talked about a many-to-many relationship:

/models/playlist.js

export default DS.Model.extend({
  name: DS.attr(),
  songs: DS.hasMany('song'),
});

/models/song.js

export default DS.Model.extend({
  name: DS.attr(),
  playlists: DS.hasMany('playlist'),
});

Then to add a playlist to a song:

function addSongToPlaylist(song, playlist) {
  song.playlists.push(playlist);
  return song.save();
}

In a relationship you always change both sides. In a relational Database you usually have a song_in_playlist table to represent the many-to-many relationship. But you don’t need this in your Ember applications.

Also in many cases your records are filtered for a User. Or some tables are not relevant for the client application so you don’t publish them. ACLs for example. But this 100% depends on your use case.