JSON Patch support for Ember Data

JSON Patch support for Ember Data

Create an extension (micro library) for using models that have individual ‘updatable’ properties. Also receive patch operations in response to updating or deleting records, (PUT or DELETE) request(s); pushing partial changes into the store. The library will need to augment prototypes for: DS.Model, DS.RESTAdapter & DS.RESTSerializer. Perhaps include application initializers to reopen the (class) prototypes to augment them with mixins which add this functionality.

Problem

A solution is needed to minimize the occurance creating a stale cache in memory as many records change. And, to prevent clobbering current changes (in progress) while editing a complex web form a solution is needed to respond to related changes in a record or in many changed records.

Data relationships that persist foreign keys, e.g. (related_ids or related_id) often need to be updated after the related record(s) change.

Related records may contain cached properties to prevent extraneous HTTP requests. As related records are updated their associated records may need an update as well.

Related records may be saved in a batch (bucket) process. Aside from the batch, new related records can be created. Many records in a complex web form can be persisted asynchronously.

A workaround that is used is manually reloading related records after completing an update (PUT request).

Use Cases:

  • When a (parent) record is edited using a web form, and a (related) record is added which requires the parent to be updated (patched or reloaded), an undesirable result may be that the parent record’s attributes are overwritten.

  • When a related record is deleted a parent record may require that the foreign key of deleted record be removed from it’s list of relations (record array). Thus a parent record needs to receive an update (perhaps a patch operation). Likewise, when a new record is added, it’s id needs to be tracked.

  • When records are related using a “has and belongs to many” (HABTM) association, foreign keys are stored on both of the related records. A list of related records may be used as the sort order for displaying the associated records by rendering a template with an each iterator. When a related record is created or removed the associated record(s) requires an update to the list of associations.

  • When records are related with an ‘async’ option; in order to serialize the record with an acurate list of related ids, every related record’s promise must be resolved first. Instead of using Ember Data relationships, perhaps using computed properties would provide synchronous access to the list of related ids when serializing.

  • When the RESTAdapter makes a PUT request and the server returns a payload the serializer’s extractSingle or extractArray which normally expects the complete payload, not a partial, see DS.RESTAdapter.html#ajax. Perhaps a 206 (partial) repsonse can be supported using DS.Store.html#update to update the related records.

Each one of these cases may involve creating, updating or deleting using RESTful requests. It may be possible for a server to return a payload that has changes to be applied to the application’s store (distributed cache, in memory). Some of the cases above may include implementations on both the client and server. Perhaps server responses can be tuned to supply the necessary changes after PUT and DELETE request complete.

Solutions

One solution to the problem of saving many records asynchronously and enforcing an order of operations, may be using a strategy like Ember.DAG provides, a Directed acyclic graph used by the Ember.Application#initializer method to order the instantiation of objects for initialization (uses before and after settings for each object that is initialized).

Another solution may be to create functionality that supports JSON Patch operations. Using the JSON Patch specification, rfc6902, for change operations, a model can mangage updates on a per property basis with (HTTP) PATCH requests.

Instead of sending a request with a complete document, a patch operation can be used to persist individual property changes. Upon success of the patch operation, which includes a test to verify the record is not stale, the record may transition to a clean state. The model’s state machine may be augmented to add isPatching[Property] sub-states that can be used to disable web form inputs or other action buttons; or perhaps using flags for each field that represent the state of that field, active or disabled.

Technical Considerations

  • Mixin for (Ember Data) DS.Adapter/DS.Serializer for PATCH requests
  • Mixin for DS.Model to support changes that fire PATCH requests
    • Use fake computed properties for the form fields
    • Use flags or states to indicate the active or disabled status for properties

Acceptance Tests

Given a Web form representing an existing record

When a change to a form field is triggered by exiting the field
Then a REST adapter handles a PATCH request using a replace operation
And while the field is patching it is disabled (editing prevented)

When a change is made that results in updates to related records
Then the server responds with the necessary operation to update the related records
And the client application patches the records, users may notice the update or not

Given a change set, operation(s) sent in response to an update or delete (HTTP) request

When the client application has the related record(s) in its store (memory cache) needing an operation
Then the store updates its cache according to the operations

When the client application does not have the related record(s) in its store (memory cache) needing an operation
Then the store’s adapter makes a request for the records needing an operation

Discussion

  1. Explore responses to PUT and DELETE requests, then update the records with the payload contents, based on response status 200 (complete representation) or 206 (partial representation of the resource).

  2. Explore using JSON Patch spec for payloads using HTTP PATCH requests to update properties as fields change (after user exits the field).

  3. Explore using JSON Patch spec for payloads sent with a 206 status, then update the records as the patch operations indicate.

  4. Is a graph object needed which provides strategy for processing patch operations. If all models can patch at the property level then it may not be necessary to enforce an order of operations.

IN PROGRESS

3 Likes

This looks good!

Would you mind submitting this as an official RFC at this repo?

@machty thanks, I added a PR, https://github.com/emberjs/rfcs/pull/5