-
Notifications
You must be signed in to change notification settings - Fork 19
Relationship Editing
With a persisted resource (model) methods are available to modify the resource's relations, addRelationship
, addRelationships
, removeRelationship
, and removeRelationships
, see the API Docs.
These methods do not persist the changes, they only modify the relationships
data
stored in the resource. The resource keeps track of it's relations by storing the "resource identifier objects" (type, id).
For a to-one
relation the data
is an object (having one resource identifier object or null); and for a to-many
relation the data
is an array of resource identifier objects, or an empty array.
See the specific methods to use based on the relationship type. The relationships
property of the resource looks just like the payload you would expect that is defined by the JSON API 1.0 Specification. The data
path is like 'relationships.' + relationName + '.data'
the relationName
would be singular for a to-one
relation and plural for a to-many
relation.
Also, you may just check if the data is an Array
if so it's a to-many
relation, otherwise the relation is to-one
. The promise proxy object that is assigned to the resource using the toOne
or toMany
Resource helper methods to define a property have the kind
of relation set, i.e. toMany
or toOne
.
There are various options to consider when editing Relationships…
Use the store or service patchRelationship
method.
The JSON API 1.0 Specification indicates that a PATCH request can be used to create/update/remove a to-one
relation.
When creating or adding the payload will include a "resource identifier object" (type and id) assigned to the data
node.
When removing the payload will assign null
to the data
node.
Use the store or service createRelationship
method to add a to-many
relation.
When creating (adding) a new relation the adapter will make a POST request that includes a array assigned to the data
node which includes one "resource identifier object" (type and id) - the relation to be added.
Use the store or service deleteRelationship
method to remove a to-many
relation.
When removing a relation the adapter will make a DELETE request which includes a array assigned to the data
node which includes one "resource identifier object" (type and id) - the relation to be deleted.
Use the store or service patchRelationship
method to replace app of the to-many
relations.
The JSON API 1.0 Specification indicates that if the server does not support replacing all of a resource's relations that a 403 response must be returned. Otherwise, the PATCH request will result in a total replacement of all the relations.
When replacing all of a resource's relations the adapter will make a PATCH request which includes a array assigned to the data
node which includes one or more "resource identifier object" (type and id) - the relations to replace the existing ones.
Mixin to provide interations between a Resource instance and service/adapter.
- Methods:
createRelationship
,deleteRelationship
,updateRelationship
The methods have built in rollback and offer a callback to handler errors. Also they provide an example of how you can create your own methods to operation on the relationships using the related services.
Ember-jsonapi-resources does not implement Active Record (like) behavior. The library is only concerned with the API contact (the JSON API syntax, format and nomenclature). So the conventions followed for operating on relationships, to-one
(has-one) and to-many
(has-many), are about working with the expected JSON format in the client app, not about active record conventions.
The Resource (model) and Adapter provide an interface for interacting with the API to operate on a resource's relations. Because the Resource does not provide Active Record (like) behavior for modeling relationships, the app developer is free to work with relations as they see fit regarding the application needs - i.e. does a relationship eagerly load, or not? Does editing a relation result in an optimistic or pessimistic representation on screen? (Are changes made to a relation applied only after an API request is successful? Or, is the change to the relation applied and rendered straightaway?)
The toOne
and toMany
helpers for a Resource (model) simply setup the PromiseProxy
object/array. The actual related resource must be requested in order for the relation's Promise
to resolve. Because Array
|Object
-Proxy
objects use a content
property to store the proxied object/array - the relation can be found at model.relation-name(s).content
.
The JSON API spec has very clear instruction on how to operate on relations, which depend on a Resource's to-one
or to-many
type of relationship. See the available Adapter
methods which are callable from the resource itself via patchRelationship
, createRelationship
, updateRelationship
, and deleteRelationship
methods which are defined in a ResourceOperationsMixin
In addition to persisting relationship changes separately from PATCH'ing a resource's attribute(s) by using the the service (adapter) methods mentioned above, the updateResource
has an optional second parameter includeRelationships
to provide an array with a list of relationship names that should be PATCH'd using the resource's link (endpoint). This optional argument, provides a way to update attributes and/or relationships together using the main endpoint for the resource.
The Resource has addRelationship
and removeRelationship
methods for operating on it's relationships
(internal hash which follows the format of the JSON API spec). The Resource also has methods that interact with the service (decorated Adapter) using a ResourceOperationsMixin - patchRelationship
, createRelationship
, updateRelationship
, and deleteRelationship
. See the section above on the "API Contract".
Instead of defining how you must work with relationships in the client application, the above mentioned Resource methods for operating on relationships provide an interface for defining how your relationships should behave according to your application needs.
Often you may decide to re-define the addRelationship
method to create the desired behavior for how your relationships should interact. In some cases you may want to load an incomplete representation of a list of resources to use as options to select from when assigning a relation to a resource. In this case the resource is new (id-less) and needs to fetch the relationship by an id in order to render the properties found in the related resource. So, after the relation assignment is made the app can fetch the complete representation. In other cases you may want to be more explicit and optimistic, assigning a loaded and complete representation of a relation to a resource and rendering immediately by setting the model.relation
(to-one) or adding to a model.relations
(to-many) array.
These various methods can be used as-is; or perhaps redefined according to your applications need(s). For example when a resource is new, and a list of relations are known only by reference (id
and a displayName
, an incomplete representation) the addRelationship
method should also do the work to request the complete representation.
/**
@method addRelationship
@param {String} related - resource name
@param {String} id
*/
addRelationship(related, id) {
if (this.get('isNew')) {
this.get('store').find(related, id).then(function(resource) {
this.set(related, resource);
}.bind(this));
}
return this._super(related, id);
},