RESTful JSON + Dojo Data June 13th, 2008 at 12:03 am by Kris Zyp

jsonreststore-simple.png
Dojo 1.2 now includes an infrastructure for interacting with JSON REST services and data storage systems. JsonRestStore is a new Dojo Data store for interacting with the RESTful JSON data sources. This new data store allows you to communicate with server side database/persistent data storage using the Dojo Data API with JavaScript and efficiently handles create, read, update, and delete (CRUD) operations. This can greatly simplify client server communication, interacting can be done simply using straightforward JavaScript instead of having to build your communication for CRUD actions. In addition, Dojo data stores can plugin to many Dojo widgets (Dijits).

Complex database driven widgets can be utilized with minimal coding effort. RESTful JSON is an increasingly popular database interface, and in later posts we will look at how JsonRestStore can be used with Amazon S3, CouchDB, Persevere, and Ruby on Rails. The JsonRestStore fully implements the Dojo Data read, write, notification, and identity interfaces. Therefore it can be used with any widget that can utilize these data stores including widgets with editing and live auto-updating features.

Also new to Dojo 1.2 is the ServiceStore. JsonRestStore is an extension of ServiceStore. ServiceStore provides Dojo Data read and identity interface for remote web services. However, I will primarily focus on the JsonRestStore in this article.

Using a JsonRestStore

The JsonRestStore can be created with a REST service function, or it can be instantiated directly with a target URL. To get a JsonRestStore instance with a target URL:

recipeStore = new dojox.data.JsonRestStore({target:"/recipeStore"});

A JsonRestStore can be created from a REST service function which can be generated with dojox.rpc.Service:

services = dojox.rpc.Service("/mySMD");
recipeStore = new dojox.data.JsonRestStore({service:services.myRestService});

jsonrest-servicestore.png

Fast and Compact Syntax

While you can use JsonRestStore and ServiceStore as you would another data store, they have been designed to support a more compact syntax for data interaction as well. This can be very beneficial if you have extensive code that interacts with the data store. First, several of the commonly used store methods are available as “static” functions, including getValue and setValue. Therefore we can easily define a convenient global or local functions for common operations.

The get, set, and save functions can be used with multiple JsonRestStore stores; it is not limited to the JsonRestStore from which it was retrieved.

With a few simple guidelines, you can actually interact with JsonRestStore items using standard JavaScript property syntax. JsonRestStore items are actually simple JavaScript objects, therefore you can always directly read properties from items.

get = recipeStore.getValue;
set = recipeStore.setValue;
save = recipeStore.save;
... // fetch an item
get(item,"foo"); // instead of using recipeStore.getValue(item,"foo");
set(item,"foo","bar"); // instead of using // recipeStore.setValue(item,"foo","bar");
save();
value = item.foo;
// instead of calling value = recipeStore.getValue(item,"foo");
var prop = "baz";
anotherValue = item[prop];
// instead of calling value = recipeStore.getValue(item,prop);

You can also modify properties of items using standard JavaScript syntax. However, in order for the JsonRestStore to know that an item has been modified, you must call the changing() method prior to modifying properties. Once you have called changing(), the object will be denoted as being dirty and you can make as many changes to the object (the object’s properties) as you want until you call the save() method. Once you call the save() method, you need to call changing() again before modifying an item again. Note, that it is safe to call changing() multiple times.

recipeStore.changing(item);
// mark item as dirty
item.foo = "bar";
// instead of calling value = recipeStore.setValue(item,"foo","bar");
item[prop] = 4;
// instead of calling value = recipeStore.setValue(item,prop,4);
recipeStore.save();
// this always must be called to commit the changes,
// regardless of whether you use setValue or not.
Property Access Performance Comparison

Browser Direct
Property
Access
JsonRestStore
getValue
ItemFileReadStore
getValue
FF3 0.037µs 1.44µs 6.3µs
FF2 0.047µs 1.75µs 9.1µs
Safari3 0.055µs 1.10µs 4.1µs
IE8 0.28µs 3.0µs 13.7µs
IE6 0.28µs 5.0µs 21µs

If you are writing extensive code based on a data store, this can make your code much more compact, readable, and maintainable. In addition, there are significant performance benefits from direct property access. Property access is 10-50 times faster than using getValue. For large or computationally intense use of data stores, direct property access may be very important for optimal performance.

There are a couple of things to remember with direct property access. First, setting properties directly does not trigger notifications. Since setting properties is usually much less frequent than reading properties, it is recommended that in most situations that you only use direct property access for reading, and use the standard simple setValue (or a convenience copy) for writing.

Also, the JsonRestStore architecture supports lazy loading using JSON referencing. When a value is accessed that is referenced, but not yet loaded, the property value can be tested with the isItemLoaded function. You can load and access the value by calling the loadItem function. You can also use the standard getValue method (or a copy of it as demonstrated above) in situations where the property may be lazy, and the getValue method will automatically download the value on demand. If you are not using JSON referencing and lazy loading you can always directly access properties using normal JavaScript syntax. However, if you are using lazy loading, when a property value is a lazy loaded you can test for values that have not been loaded and load them asynchronously:

myValue = item.foo;
if(recipeStore.isItemLoaded(myValue)){
	recipeStore.loadItem({item:myValue,onItem:function(result){
		... resume with result ...
	}});
}

or simply using synchronous loading (for lazy loaded properties, the Dojo Data getValue function is the easiest form of access):

myValue = recipeStore.getValue(item,"foo");

Remember, this is only necessary if you are using lazy loading via JSON referencing. Also, using direct property access is purely optional, you can use the JsonRestStore with the same API as any other Dojo Data store.

JsonRestStore also provides a constructor for aesthetic creation of new objects. This constructor is accessible with the getConstructor method:

Recipe = recipeStore.getConstructor();
// create a new recipe object instead of recipeStore.newItem();
var recipe = new Recipe();

The constructor also includes a load function for convenient access to the Rest service querying and fetching items by id.

Now we can put this all together, If we first create aliases for getValue, setValue, save, and changing and then create the Recipe constructor we can write:

// make Apple Pie
var query = Recipe.load("?type='Pie'"); // query for the recipes for pie
query.addCallback(function(queryResults){ // when the results are returned
	var recipe = queryResults[0]; // get the first result
	if(recipe){
		if(recipe.name!="Apple Pie"){ // get the name property
			changing(recipe); // indicate we are changing properties
			recipe.name = "Apple Pie"; // rename this recipe to apple pie
		}
	}else{
		// create a new Recipe for apple pie
		recipe = new Recipe({name:"Apple Pie"});
	}
	save(); // save our changes to the database
});

JsonRestStore and ServiceStore also support synchronous mode. Synchronous requests can create a poor user experience since they generally lock up the browser while the browser waits for a response from the server. However, synchronous mode can also simplify programming. Since it is not necessary to use nested callbacks for handling responses, they can be accessed directly after making a request inducing call. Firefox 3 has also eliminated the browser lock-up associated with synchronous calls, making it a more attractive mechanism. To use synchronous mode, you include the syncMode option when instantiating a data store:

recipeStore = new dojox.data.JsonRestStore({target:"/data",syncMode:true});

In synchronous mode, one can fetch without providing a callback, by directly accessing the results property from the request object that is returned from the fetch operation:

var queryResults = recipeStore.fetch({query:"?tastes='good'"}).results;
var firstItem = queryResults[0];

Implementing a RESTful JSON Server

The JsonRestStore can be used with a number of server storage systems that support HTTP JSON/REST interface without any server-side coding. Several JsonRestStore extensions designed to easily connect with Persevere, CouchDB, and Amazon S3 with minimal configuration are included with Dojo 1.2. You can also easily create your JSON/REST interface for an existing web application and database. This is essentially done by implementing the HTTP methods GET, PUT, POST, and DELETE according to the HTTP specifications and providing the data in JSON format. While the JsonRestStore can be configured (using dojox.rpc.Service) to support other configurations, generally rows/items/objects should be accessible using URLs of the form /table/id. GET is used to retrieve objects and perform queries, POST is used to create new objects (by POSTing to /table/), PUT is used to modify objects, and DELETE deletes objects. You can also follow the example used by other JSON/REST interfaces like Persevere and CouchDB.

Transactions

JsonRestStore provides transaction state information so that servers can implement transactions that correspond to the Dojo Data it saves if desired (this is not necessary for a server to implement in order to support REST). Transactions are indicated by a X-Transaction header in the modifications requests. If the X-Transaction header has a value of open, this means that further requests will be delivered that should be included in the current transaction. Once a request is received without an X-Transaction header of open, the server can commit all the changes from the current request and the previous requests that indicated an open transaction. It is recommended that you utilize deterministic request ordering and page sessions if you implement JsonRestStore directed transactions on the server.

JsonRestStore also features a shared repository of transactional data between all JsonRestStore instances. Therefore, if you save a change, all the JsonRestStore data store’s unsaved data will be committed. This means that you don’t have to track which data stores have modified data, and it also means that you transactions can involve modifications across multiple data stores and corresponding server tables.

Build with, not on JsonRestStore

The JSON REST infrastructure is composed of a layer of modules that can easily be utilized and extended on their own, following the Dojo philosophy of extensibility. First, JsonRestStore is an extension of the ServiceStore data store and is designed for provider/store separation. The ServiceStore is a read-only data store built such that various different remote data providers can plugin to the ServiceStore. Thus the ServiceStore provides an adapter between the remote communication provider and widgets. Within dojox.rpc, several commonly used remote communication plugins are provided including REST, JSON-RPC (version 1 and 2), JSONP, and direct POST and GET. You can also easily create custom remote data providers, by creating a service function that takes parameters and returns a dojo.Deferred object that will receive the result of the query. These can all be used with the ServiceStore. The demonstration of using ServiceStore with a Yahoo search web service shows this in action. You should use the ServiceStore whenever you are working with a read-only web service (that doesn’t support full bi-directional REST), as it is lighter than JsonRestStore.

yahoo-search-demo.png

ServiceStore only provides read capabilities (the Dojo Data Read API), however, writable remote communication providers (REST services) can plugin to the JsonRestStore for full read-write capability. A writable provider is one that provides put, post, and delete functions as properties of the main retrieval function. Once again, you can use the HTTP/REST compliant provider included with Dojo (dojox.rpc.Rest) or you can create your own.

Build with REST Infrastructure

dojox.rpc.Rest can also be used directly. A REST service can be constructed with dojox.rpc.Rest:

var restService = dojo.rpc.Rest("/myRestTarget",true);

This indicates that the rest service can be found at /myRestTarget and it is a JSON service, which enables additional caching and optimization capabilities. You can retrieve data from this service:

restService("10") // retrieve the object with an id/resource location of 10

This would result in a fetch from the local resource /myRestTarget/10. You can modify this resource with a PUT:

restService.put("10",{foo:"bar"});

This will store the provided JSON object into the target resource. You can also use restService.post and restService.delete to further directly modify resources. JsonRestStore uses these access points to persist all data changes in the data store. New objects are added with a service.post, deleted objects are removed with a service.delete and modifying objects are updated with a service.put.

jsonrest-infrastructure.png

The dojox.rpc.JsonRest module is the core engine behind JsonRestStore. JsonRest can be used directly, providing a compact API with the core features of JsonRestStore, including transactional data interaction and query and object loading. dojox.rpc.JsonRest is a singleton object, and provides functions: fetch, commit, revert, changing, deleteObject, getConstructor, and isDirty. These correspond to the same functions on JsonRestStore, but the single JsonRest object can be used without requiring separate data stores to be used to access the API. If you do not need the Dojo Data API, and you only need JSON/REST interaction, you can go lighter, and directly interact with dojox.rpc.JsonRest. However, because the Dojo Data API enables you to plug stores into numerous widgets with minimal effort, generally using JsonRestStore is preferable to directly using JsonRest.

JsonRestStore also has comprehensive referencing capabilities, including circular, multiple, and cross-store, and cross-site references. This feature is also provided by a separate JSON referencing module, dojox.json.ref for modularity and extensibility. Therefore, you can use the JSON referencing module to resolve and serialize references for data exchange outside of JsonRestStore. For example, you could easily use referencing for JSON-RPC data, and even allow RPC parameters and return values that reference data from REST stores. This modular structure also allows you to extend or use alternate referencing conventions for JsonRestStore.

Live and Offline Data Stores

Because the JsonRestStore uses the extensible Rest service, JsonRestStore also works with HttpChannels, the new cometd transport/protocol module, to provide a Comet-powered real time view of data on a server. This does not require writing any additional event handlers. If you are using a server that supports HTTP Channels (like Persevere), you can simply add the HttpChannels and you can will have a live view of your data. Be sure to check out the JsonRestStore in action with live updates.

Likewise, JsonRestStore will also run in offline mode by simply adding the forthcoming dojox.rpc.OfflineRest module. The OfflineRest module augments the REST service. As a result, a JsonRestStore running off of a REST service will automatically be able to run in offline mode, with data changes saved locally when offline and automatically re-synced when connectivity is restored.

Dojo 1.2 now has a comprehensive infrastructure for RESTful interaction with servers. JsonRestStore is a modular data store with built in capabilities for interacting with servers in standards-based manner that already works with a number of existing server technologies, and provides a widely usable data store for server side storage that is easy for servers to interact with. Stay tuned for more posts on using JsonRestStore with various storage servers.

Tags: , , ,

42 Responses to “RESTful JSON + Dojo Data”

  1. Michael Marth says:

    Hi, nice post. To see how to integrate with Jackrabbit have a look here: http://dev.day.com/microsling/content/blogs/main/dojosling101.html

    Cheers
    Michael

  2. kzyp says:

    Michael,
    Yes, I have seen Sling’s data store. Do you think the Sling server is REST/HTTP compliant enough (and in JSON) to work with the JsonRestStore? I would love to be able to connect to Sling if possible.

  3. Pratik Patel says:

    Where is this mystical Dojo 1.2 release? http://download.dojotoolkit.org/ turns up 1.1.1 as both the stable and development release… even google can’t find it!

  4. Dylan says:

    Dojo 1.2 will be released in July. For now, you can head to http://archive.dojotoolkit.org/nightly/ to download the latest Dojo pre-1.2 snapshot.

  5. Pratik Patel says:

    looking forward to the release, jsonreststore and a few other things look really cool!

  6. Medryx Observations » Blog Archive » Pseudo-RESTful says:

    […] loading that I thought was going to be the greatest thing since… well anyway. Then I read this , and realized that there was no need to write almost any of what I had written. I hate when that […]

  7. Medryx Observations » Blog Archive » An Object-Relation-Mapper (ORM) for Javascript? Well, kind of… says:

    […] an aside, I was excited when I first read about the JsonRestStore.. Indeed, it probably does a lot of this same work. So it may be an issue of style. I also […]

  8. Vilas says:

    Do you an example of how REST / JsonRestStore can be used to read/write/update/delete items stored in a grid? It will be really helpful.

  9. kzyp says:

    Vilas,
    I would gladly do a post with more comprehensive examples of using JsonRestStore with widgets, but briefly it is as simple as plugging the store into a grid and then the standard Dojo Data API commands will auto-update the grid. For example:
    <table dojoType=”dojox.grid.DataGrid” store=”recipeStore”> … table headers … </table>

    And then:
    recipeStore.deleteItem(item) // will remove a row from the grid
    recipeStore.newItem(item) // will create a new row in the grid
    recipeStore.setValue(item,prop,value) // will update a row in the grid

  10. SitePen Blog » Amazon S3 + Dojo says:

    […] Not only that, Amazon S3 is a REST service and therefore it can be used as a data store with Dojo’s new REST implementation of dojo.data, JsonRestStore. You can read and write to your S3 database using the convenient Dojo Data API, and use the data […]

  11. Comet Daily » Blog Archive » Dojo HttpChannels Module says:

    […] easiest and highest level use of HTTP Channels is in conjunction with the JsonRestStore. HttpChannels can be used as an enhancement for the REST service, to enable “live” data […]

  12. Steven says:

    This is a great ! Dojo is absolutely the pioneer implementing the new technologies.

    I just tried to use the JsonRestStore with the tree model and dijit.tree. It looks it is not as simple as just plugging it to dijit.tree. Some massage seems needed, but I could not figure it out. Could you talk about it in your next post regarding JsonRestStore?

    Good job !

  13. kzyp says:

    @Steven: I can try to include instructions for using it with a tree in the next post about JsonRestStore. However, I think the primary prerequisite for the tree is that the items/objects in the JsonRestStore have a “children” property that has an array of the list of children.

  14. steven says:

    Kris, thanks for the reply. I also find the lazyloading feature does not work properly. The code is like this:

    var store = new dojox.data.JsonRestStore({target: “/something/”});
    var args = {
    query: 1, // it does generate url like GET “/something/1″
    onItem: function(item){
    console.debug(”item is ” + item.label)
    },
    onError: function(err){
    console.debug(”error occured “)
    }
    };
    var item = store.fetch(args).results;

    The json sent back from server is like:
    { “id”: 1,
    “parentId”: 0,
    “label”: “something_1″,
    “type”: 1,
    “children”: [
    { “$ref”: “3″},
    { “$ref”: “5″},
    { “$ref”: “7″}
    ]
    }

    // get first referred object
    var kid = store.getValue(item, “children”)[0]

    It does NOT issue a xhr call to lazy load the referred objects.

    the properties of kid is like:
    Methods: _loadObject
    Fields: $ref, __id

    I check that store.loadLazyValues has been set to true.

    Also, the usage of store.fetch and store.byId(aliased to fetchItemByIdentity) are confusing. For example, the query to store.fetch , like {query: 1}, generates the same url(/something/1) as store.byId({identity: 1})

    I feel I had mistakes using store. It would be great if some documents are available.

    Thanks

  15. kzyp says:

    @steven:
    JsonRestStore does not do recursive loading of all children when you do a getValue. In the example, store.getValue(item, “children”) returns an array that is loaded, but the children (array items) of the array are not loaded. You should be able to do:
    store.getValue(store.getValue(item, “children”),0);
    Of if you know that children is not lazy, as in your example you can simply do:
    store.getValue(item.children, 0);
    Or alternately you can avoid synchronous calls:
    store.loadItem({item:store.children[0],onItem:function(loadedChild){
    ….
    });
    All of these should trigger a request for “3″.

  16. kzyp says:

    @steven:
    Also, in regards to byId behaving the same way as query, this is by design. JsonRestStore is intended to be query string agnostic, you can use any query string style you would like, both queries and identity lookups simply map to URL requests.
    Also, the last example from my last comment had a typo, it should be:
    store.loadItem({item:item.children[0],onItem:function(loadedChild){
    ….
    });

  17. SitePen Blog » Getting Started with Persevere Using Dojo says:

    […] is compliant with the HTTP/REST protocol, so the JsonRestStore is very effective with Persevere. However, dojox.data.PersevereStore is an extension of […]

  18. REST and TG at Compound Thinking says:

    […] And then HTTP GET and POST verbs will be routed to their respective methods. This makes working with RESTFul api’s easier. And on that front I’m very much looking forward to Dojo 1.2 which has all of kinds of restful json data store goodness. […]

  19. steven says:

    Kris, super good reply ! Another question. The result from asyn fetch should be accessed via the deferred object that containing the returned result. In JsonRestStore, the only way, I find so far, to get that deferred object is from the store.getConstructor.load method, like the following code in your blog

    var query = Recipe.load(”?type=’Pie’”); //query is the deferred obj

    To get the deferred object for returned data is important in asyn mode. Is there any other obvious(I mean ‘obvious’ by comparing to the load method hidden somewhere) way to get it?

    Many thanks.
    Is there any other way to get that deferred object?

  20. kzyp says:

    @steven: With the JsonRestStore you can use the fetch according the dojo.data.api.Read API (http://api.dojotoolkit.org/jsdoc/dojo/HEAD/dojo.data.api.Read.fetch) for async loading, for example:
    store.fetch({query:”?type=’Pie’”,onComplete:function(results){

    });

    fetch doesn’t return a Deferred object because fetch includes support for progressive loading and Deferred doesn’t.

  21. Maulin Shah says:

    I’ve written up my take on JsonRestStore and using it for non-REST web services. Hope its helpful to someone!

    http://blog.medryx.org/2008/07/24/jsonreststore-overview/

  22. steven says:

    Kris, I find a problem of using method newItem. Let’s say:

    store.newItem(data, parentInfo);
    store.save();

    The new item is added to store with a random number in place of id of ite __id propery, like this:

    “__id”: “/resource/99e23f01ac40c7d883b01818″

    This value of ‘__id’ property will be used as the url for the further xhr request upon any update(editing, or adding its children item) to this new item. The random number in __id is done on purpose in the source code. I guess this intends to leaves the chance to user to replace the new item’s id with “actual” id, while the “actual” id should be determined by server and derived from the returned new item from server.

    This is perfect due to this flexibility its leaves to user. However, I could not find it any where on how to have the replacement of values of “actual” id and __id take place. One place I realized is the function onPostCommit, which seems to aim for this purpose but it is not been implemented (I already file a bug report in trac for onPostCommit).

  23. kzyp says:

    onPostCommit is intended to be implemented by subclasses (it is ignored otherwise). I can update JsonRestStore? to update objects based on the ids assigned by the server (per the HTTP spec, this should come from the Content-Location header). However, I have been hesitant to code this because it is such a fragile solution. If you create a new item and save it (triggering a POST), and then make a modification and save it before the first save’s response is received, it is impossible for the JsonRestStore? to know the assigned id. It would be possible to delay the second save until the first save is received, but this would significantly increase the size and complexity of the code, so I will surely avoid this solution. There is also additional complexity because we can’t change the client reported id (from getIdentity(item)) or it will break widgets, so must retain the client assigned id for getIdentity calls. Consequently, I believe it is better for the server to maintain a session based temporary map of client ids that map to the assigned server ids. However, I can still code this change for those that want to use it.

  24. kirlian says:

    Hi,

    If we have 2 jsonreststore, how to update only one ?

    Arnaud.

  25. kzyp says:

    @kirlian/Arnaud: The JsonRestStore has been designed to treat transaction like databases do, transactions are not local to a single table or store, but span table/stores. If there is a desire to have commits that only affect a single JsonRestStore, I can add a configuration setting to support that option. I would love to know what the use case is that demands such an option though.

  26. kirlian says:

    Hi,

    Thanks for your answer.

    The main subject is the order of the transactions. How can we say to 2 jsonrestore that an insert or update must be done first on this table and second on another table ? And in case of deletion this is the opposite ? The workflow in the screen to key in data can be different from the workflow to insert data in the database.

    If we take as example a screen wich display an order.

    There is two sections : the first one with the entity data (name of supplier, order date…) and one grid with the detail of article.

    In that case, there is one jsonrestore for the entity data and one for the grid.

    To create a new order, the entity must be created before the details in the database to respect database constraints. If we have two controllers “entity_order” and “detail_order” how to do without having commits that only affect a single JsonRestStore ?

    Arnaud.

  27. kzyp says:

    @Arnaud: I just checked in a fix for JsonRestStore, it should now default to saving only the data for that particular store (but you can still global saves with the “global” option).

  28. kirlian says:

    Hi,

    Thanks for this fix, it was really important according to me.

    If I can suggest you another enhancement : to allow to commit for a jsonreststore only updated items, deleted items or created items.

    Usually when you have 2 tables linked, the order to make the insert is the opposite than the order to make the delete and their is no order for the update.

    Arnaud.

  29. JSON » Blog Archives » Dojo 1.2 Beta Available says:

    […] I am particularly excited about this release because it includes JSON referencing support , the JsonRestStore module, a JSON-based client REST implementation , JSONQuery , the windowName module , Dojo Secure , and much more . Posted in Announcement, […]

  30. ben hockey says:

    i’m having a problem getting this to work. to avoid filling up your blog, i posted in the forums - http://dojotoolkit.org/forum/dojox-dojox/dojox-support/jsonreststore-expected-data-format-0 could you take a look at it for me?

    thanks.

  31. steven says:

    Krys,

    Your modification to JsonRestStore regarding onPostCommit is exactly what we need. Thanks !

    Here is another question which might look silly…

    When testing JsonRestStore, in the smd file:

    {
    services: {
    jsonRestStore: {
    transport: “REST”,
    envelope: “URL”,
    target: “fakeserver.php”,
    contentType:”application/json”,
    parameters: [
    {name: “location”, type: “string”, optional: true}
    ]
    }
    }
    }

    In the target property, where to put fakeserver.php file. Is it relevant to the smd file, or it has to be a full path of url(which means the web server needs to be up, but this seems to break the rule of cross-domain access)?

  32. kzyp says:

    @steven: The URLs in the SMD are relative to the SMD file, so it is fine to do:
    target: “fakeserver.php” or target: “/fakeserver.php”.

  33. SitePen Blog » Effortless Offline with OfflineRest says:

    […] online, otherwise when connectivity is restored. Furthermore, JsonRest is the core engine used by JsonRestStore. Consequently, you can simply use the standard Dojo Data API with the JsonRestStore and […]

  34. steven says:

    Hi Kris,

    The fakeserver.php just works for me. Thanks ! Two more questions.

    In dojox.rpc.JsonRest, starting at line 84:
    var newId = dfd.ioArgs.xhr.getResponseHeader(”Location”);
    if(newId){ object.__id = newId;
    var objectId = newId.match(/\/([^\/]*)$/);
    if(idAttr && objectId){
    object[idAttr] = objectId[1];
    }
    Rest._index[newId] = object;
    Should the server set the header[”location”] with the prefix of servicePath for newId? Because Rest._index is shared by all stores, the newId should have servicePath as prefix, otherwise it would mess up Rest._index. Is this correct?
    Why is __clientId not set with newId in the same time? In JsonRestStore.js, the function getIdentity checks the property of __clientId.
    getIdentity: function(item){
    var id = item.__clientId || item.__id;
    more codes …}

    If the new item does not get refreshed by being reloaded from server, __clientId of the new item would remain like /service/path/78dafd6899, and therefore getIdentity would get the wrong id of the new item.

  35. kzyp says:

    @steven: JsonRestStore expects the Location header should to be an absolute path, like that the absolute paths used by __id (”/table/id”).
    getIdentity() must always return the same value for a given item. This is an invariant that many widgets rely upon. The reason for the __clientId property is so that even after the id is updated, getIdentity() can still return the same value. If getIdentity() changes its return value widgets like the Grid will break.

  36. SitePen Blog » CouchDBRestStore says:

    […] of the stores built on JsonRestStore and included in Dojo 1.2 is the new CouchDBRestStore. CouchDB server is a JSON-based schema-free […]

  37. SitePen Blog » Jaxer + Persevere via Dojo’s JsonRestStore says:

    […] based object model with object persistence. Dojo’s new PersevereStore, which is built on the JsonRestStore, allows code running in Jaxer to easily query, manipulate, and interact with data in Persevere by […]

  38. Medryx Observations » JsonRestStore — Custom Services, Schemas, and Lazy Loading says:

    […] In this article I have touched on just a few advanced features available with JsonRestStore — using a custom service, using a schema to provide an object prototype, lazily loading objects, and sparsely loading objects. But there is plenty more goodness to be found in this store! Stay tuned for an article on client-side caching and other great features of JsonRestStore! […]

  39. Release Notes zum Dojo Toolkit V1.2 - dojotoolkit-forum.de says:

    […] auch den Blog-Beitrag für mehr […]

  40. Zladivliba says:

    Great post. I tried to build this but the grid wont’ show the data with the JsonRestStore. Here’s a piece of code :

    var Service = function(query, queryOptions) {
    return dojo.xhrGet({url:”/test/”, handleAs:”json” }); }
    Service.post = function(id, value) {
    return dojo.xhrGet({url:”/test/”, content:{method:”create”, id:id, value:value}}); }

    store = new dojox.data.JsonRestStore({target:”test”, service:Service});

    // the grid
    dojo.addOnLoad(function(){

    // set the layout structure for the grid version 1.2
    var layout4 = [
    { name: “Test”, field: “post_id”, width: ‘40px’},
    ];

    // create a new grid:
    var grid4 = new dojox.grid.DataGrid({
    query: { post_id: ‘*’ },
    store: store,
    structure: layout4,
    }, document.createElement(’div’));

    dojo.byId(”gridContainer4″).appendChild(grid4.domNode);
    grid4.startup();
    });

    Now, /test/ returns this data format :

    [
    {”post_id”:”1″,”user_id”:”1″,”url”:”new-post”,”ts_created”:”2008-10-01 14:16:30″,”status”:”Live”,”profile_key”:”title”,”profile_value”:”new post”},
    {”post_id”:”2″,”user_id”:”1″,”url”:”new-post-draft”,”ts_created”:”2008-10-01 14:17:38″,”status”:”Draft”,”profile_key”:”title”,”profile_value”:”New post draft”},
    {”post_id”:”20″,”user_id”:”1″,”url”:”test-3″,”ts_created”:”2008-10-01 22:28:46″,”status”:”Draft”,”profile_key”:”title”,”profile_value”:”test”}
    ]

    I tried also to return another data format that worked using IwriteFileStore that I tried, but that got me nowhere :

    {”identifier”:”post_id”,”items”:
    [{”post_id”:”1″,”user_id”:”1″,”url”:”new-post”,”ts_created”:”2008-10-01 14:16:30″,”status”:”Live”,”profile_key”:”title”,”profile_value”:”new post”},
    {”post_id”:”2″,”user_id”:”1″,”url”:”new-post-draft”,”ts_created”:”2008-10-01 14:17:38″,”status”:”Draft”,”profile_key”:”title”,”profile_value”:”New post draft”}
    {”post_id”:”20″,”user_id”:”1″,”url”:”test-3″,”ts_created”:”2008-10-01 22:28:46″,”status”:”Draft”,”profile_key”:”title”,”profile_value”:”test”}]
    }

    Do you have any idea of what’s going wrong ?
    The grid does not display anything…

  41. kzyp says:

    The problem is that you didn’t specify an identity attribute, and
    JsonRestStore defaults to “id” as the identity property (and it
    doesn’t use the ItemFileReadStore format). You can specify the
    identity attribute in the JsonRestStore constructor:

    store = new dojox.data.JsonRestStore({target:”test”, service:Service,
    idAttribute:”post_id”});

  42. Comet Daily » Blog Archive » Using Bayeux with Persevere says:

    […] we can utilize the PersevereStore (based on JsonRestStore) to interact with the database and perform queries. Then we can use the identities from objects as […]

Leave a Reply