The JsonRestStore is a Dojo Data store that provides a JSON-based RESTful interface to servers and implements the Dojo Data read, write, notification, and identity APIs. Since its addition in Dojo 1.2, it has been a popular Data Store because of its numerous features and its standards-based implementation of the HTTP specification (RFC 2616) for communications with servers. For Dojo 1.3, JsonRestStore includes a few extra features and some of the features in version 1.2 deserve a more elaborate explanation.

Handling Dates

The latest version of the JSON referencing module used by JsonRestStore now also includes date parsing capabilities. This makes it possible to load dates from the server as true JavaScript dates. JSON lacks native date support, but dates are generally serialized in ISO format (usually with UTC timezone), following the lead of the reference implementation, and JsonRestStore supports this format. Because dates are serialized as strings, JsonRestStore utilizes a schema to disambiguate strings from dates. This is done by defining the format of a property as “date-time”. For example, you could designate the purchaseDate property to be a date and converted to a JavaScript date by instantiating the store:

var poStore = new dojox.data.JsonRestStore({target:"/PO", schema:{
   properties:{
      purchaseDate:{
        format:"date-time"
      }
   }
}});

With this schema in place, the value for the purchaseDate can be serialized from the server as an ISO date:

{
  "purchaseDate":""2008-11-11T13:27:44Z",
  "id":"3433",
  ...
}

The purchaseDate property value will be converted on the client to a JavaScript Date object. Now we can easily utilize the items in the JsonRestStore with widgets that expect Date objects.

Default Values

Another benefit that can be derived from schemas is default values for new items. Any property definition in a schema can define a default value. When a new item is created, JsonRestStore will use the default values provided by the schema as the initial values of the newly created item. For example, we define a default value in our schema:

var poStore = new dojox.data.JsonRestStore({target:"/PO", schema:{
   properties:{
      active:{
         type:"boolean",
         "default":false
      }
   }
}});

And now we can create a new item:

var aNewItem = poStore.newItem();
aNewItem.active -> false

Dates in the Grid

The Dojo Grid is designed to work with the Dojo Data API, so in order to leverage what we just learned about using dates, let’s make a grid that has an editable date field using the DateTextBox widget:

gridLayout = [
        { name: 'Address', field: 'shipToAddress', editable: true},
	{ name: 'Date', field: 'purchaseDate', editable: true,
		type: dojox.grid.cells.DateTextBox, 
		formatter: formatDate, 
		constraint: {formatLength: 'long', selector: "date"}
	},
	{ name: 'Id', field: 'id'}];
var grid = new dojox.grid.DataGrid({
	store: poStore,
	structure: gridLayout
}, dojo.byId("gridElement"));
grid.startup();

The grid will now use a DateTextBox widget when you edit a value in the Date (purchaseDate) column.

Deleting Items

For Dojo 1.3, JsonRestStore now includes reference deletion when an item is deleted. Before 1.3, when an item was deleted all references were still in place, and a user would need to manually remove any references. With Dojo 1.3, when you delete an item, JsonRestStore will search through all the items in the store and remove any references. One aspect of the JsonRestStore that should be noted is that JsonRestStore does not maintain any reference maps. This causes deletion to be slower, but this is an intentional performance trade-off done to reduce memory and maintain optimum performance on loading (data access usually occurs orders of magnitude more frequently than deletion), and eliminate overhead for those who don’t need the feature. For almost all applications, overall this is by far the highest performing approach.

Conflict Handling

One of the challenges of multi-user data systems is handling conflicting date updates. When one user updates an object at the same time as another user updates the same object, generally the server needs to mediate this conflict. JsonRestStore provides help with conflict handling in version 1.3, following the HTTP specification for conditional updates. If the data that is returned from the server includes a Last-Modified header date, by default this date will now be included in PUT requests in the If-Unmodified-Since header. In order to utilize this feature, first ensure that you are including Last-Modified header dates in your responses from the server:

Last-Modified: Fri, 21 Nov 2008 09:52:12 MST

[{"id":"13",
 ... my data ...
}]

Now when an object is modified and a PUT request is made, it will look like:

PUT /data/13
If-Unmodified-Since: Fri, 21 Nov 2008 09:52:12 MST
{... data ...}

The server can then check to see if the resource has been modified since the given date and if so, it can return a 409 Conflict error to the client indicating that someone else has modified the object and that the modification request was refused.

Another possible way to mediate modification conflicts is to merge the changes from the two users. By using the date provided by the client, the server can determine what version of an object the user was updating and calculate the differences in order to integrate those differences with the changes made by another user, essentially doing a three-way merge. The date header used by the JsonRestStore is configurable; in this situation it would be advisable to use a different header name since this more advanced behavior does not follow the semantics of the HTTP specification. The header name is configurable with the dojox.rpc.JsonRest.conflictDateHeader property. This property can also be set to null to disable the inclusion of any conflict handling date header.

JSON Referencing Updates

JSON referencing, used by the JsonRestStore, provides the ability to reference JSON elements by id and by path through the dojox.json.ref module, and is based on JSONPath. Within the REST architecture, JSON referencing is essentially hyperlinks for JSON. Id references correspond to URIs (usually relative, as in anchor tags), and path references can map nicely to in-document references as fragment identifiers. However, this means that JSON references that properly follow the URI scheme should use a fragment identifier separator # to delineate between the id/URI reference and the path reference. With this change, RESTful JSON references also have simplified the path syntax. Paths are now simply dot delimited for both string and array index references. Here are some example JSON references that are now supported by the JsonRestStore:

{“$ref”:”3″} refers to the object within the current context/store with an id of 3
{“$ref”:”3#foo”} refers to the value of the foo property for the object with an id of 3
{“$ref”:”3#foo.2″} refers to the third element of the array that is referred to by the foo property of object 3
{“$ref”:”#”} refers to the current object (or array) being loaded/transferred
{“$ref”:”#3.bar”} refers to the value of the bar property of the fourth element of the current array being loaded/transferred
{“$ref”:”http://www.json-schema.org/schema#type”} refers to the value of the typeproperty of the JSON document found at http://www.json-schema.org/schema

JSON Referencing still provides backwards compatibility with the JSONPath referencing where $ refers to the root object and the bracket index operator is used for array indices and non-letter-only property names. This JSON Referencing update is based on the discussions and efforts of the RESTful-JSON group, which is working towards standardization of a RESTful JSON protocol and format. This improvement in JSON Referencing is a step towards interoperable RESTful JSON.

In Transaction Referencing

JsonRestStore provides the ability to perform multiple actions in a single transaction. However, one of the thorny issues that can be encountered in transactions is when trying to create two new objects at the same time with references to each other. JsonRestStore 1.3 solves this problem borrowing a referencing technique from RFC 2387 (multipart/related). When new items are created, the POST request will include a Content-ID header indicating a temporary id for the item. Other items being committed in the same transaction can then refer to the item by the cid: protocol with JSON referencing. For example:

POST /people/
Content-ID: 
{"name":"Kris":"father":{"$ref":"cid:/Customer/42234"}}

POST /people/
Content-ID: 
{"name":"William":"son":{"$ref":"cid:/Customer/cdc47"}}

Creating references within a single transaction like this can be difficult to implement on the server, so you can ignore it if you don’t need it, but this mechanism is there for when you really need it.

Summary

The JsonRestStore provides a comprehensive data store with complete standards based HTTP interaction with servers, making it easy to build powerful REST-based applications. With the new features in 1.3, the JsonRestStore provides an even more robust data solution.