Medryx Observations

June 18, 2008

Pseudo-RESTful

Filed under: Uncategorized — maulin @ 10:40 am

I have to admit it: I spent the last week rolling my own data store that handles lazy 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 happens.

In any case, the new JsonRestStore does just about everything I wanted to do, only more efficiently. My only problem is that my server, which I have no control over, has blocked “PUT” and “DELETE”. But really, that seems minor. I mean, couldn’t we just include a flag to our REST server telling it what action we are expecting? Yes. We can.

A detailed look into dojox.rpc.Rest reveals that the _change method is where the final call to xhr occurs. Now I know this is unsafe since this is a private method, but its a good quick fix for now. And perhaps I can convince the dojo folks after 1.2 is official that they should support this kind of behavior for “Pseudo-REST” services, right out of the box.

Here is the code.

/**
 * 
 * uses post for all post/put/delete, but adds and attribute called action
 * 
 * @author maulin
 * 
 */
dojo.provide("medryx.stores.ModifiedRest");
dojo.require("dojox.rpc.Rest");
 
(function() {
 
  //copied verbatim from dojox.rpc.Rest -- it is local in scope inside Rest
 //and called from the _change method, so I need it (for now)
  function index(deferred, service, range, id){
        deferred.addCallback(function(result){
            if(id==""){
                service._rootQueries.push(result);
            }
            if(range){
                // try to record the total number of items from the range header
                range = deferred.ioArgs.xhr.getResponseHeader("Content-Range");
                deferred.fullLength = range && (range=range.match(/\/(.*)/|>)) && parseInt(range[1]);
            }
            return service.cache.intake(result,id);
        });
        return deferred;
    }
 
  //"over-rides" the actual xhr call to use POST and add action attribute to querystring
  dojox.rpc.Rest._change = function(method,service,id,content){
        // this is called to actually do the put, post, and delete
        var request = service._getRequest(id);
        request[method+"Data"] = content;
 
        //ADDED THE FOLLOWING TWO LINES
        request.data += "&action=" + method.toLowerCase();
        request.url += (request.url.indexOf('?') > 0 ? "&" : "?" ) + "action=" + method.toLowerCase();
 
        //CHANGED THIS LINE TO ALWAYS USE POST
        return index(dojo.xhr("POST",request,true),service);
    };
 
})();

4 Comments »

  1. May I suggest something like this for REST blocking servers:

    var defaultXhr = dojo.xhr;
    dojo.xhr = function(method,args,hasBody){
    if(method!=”GET”){
    args.url += (args.url.indexOf(’?') > 0 ? “&” : “?” ) + “action=” + method.toLowerCase();
    if(method==”PUT”){
    args.postData = args.putData;
    }
    method = “POST”;
    }
    return defaultXhr(method,args,hasBody);
    }

    That way all your requests that use PUT, POST, and DELETE will automatically have the correct “action” parameter. I didn’t test this, but I think it should work.

    Comment by Kris Zyp — June 18, 2008 @ 5:56 pm

  2. great idea. thanks.

    I actually thought about this “hack” some more, and had a more general thought: The reason I like JsonRestStore is that it has a VERY nice entity-manager (for lack of a better term). Its not that I need or want REST (I have a simple working RPC server already working with get/save/delete methods).

    I think the JsonRestStore actually has mixed concerns — on the one hand an entity-manager, and on the other a “persister”. Perhaps we could think about how to split the two, and then make REST a pluggable persister into the entity-manager?

    Comment by maulin — June 18, 2008 @ 7:29 pm

  3. Maulin,
    I am not exactly certain what you mean by entity-manager, are you referring to the mechanism for triggering lazy loads on property access and recording property changes? I am not sure how you would like JsonRestStore split up. Here is the current breakdown of modules:
    JsonRestStore - Dojo Data API adapter
    JsonRest - Tracks changes and fires Rest services
    Rest - Remote communication service provider
    dojox.json.ref - Referencing manager for lazy loading and other forms of referencing
    Perhaps JsonRest or JsonRestStore would roughly correspond to your “entity-manager”, and the Rest service would correspond to your “persister”, not sure. You can definitely plug your own custom Rest service into JsonRestStore. It looks like:
    myService = function(id){ … get data … }
    myService.put = function(content) { … save data …}
    myService.post = function(target,content) { .. create new object …}
    myService['delete'] = function(target){ … delete object …}

    If you providing getters and setters is what you have in mind for an entity-manager, you can also define schemas for JsonRestStore that define the prototype to use for the objects in the store:
    mySchema = {
    prototype: {
    getFoo:function(){return this.foo},
    setFoo:function(val){this.foo =val}
    }
    }
    myStore = new JsonRestStore({service:myService,schema:mySchema});

    Comment by Kris Zyp — June 19, 2008 @ 6:28 am

  4. Ugh. Yes. That is EXACTLY what I meant. I guess I didn’t understand this as thoroughly as I had hoped. I have created a slightly different approach to this, but now seeing how JsonRestStore is setup, I don’t know how much value add there is. We’ll see. I plan on posting about it later tonight.

    thanks again for your input.

    -maulin

    Comment by maulin — June 19, 2008 @ 6:35 am

RSS feed for comments on this post. TrackBack URL

Leave a comment

Powered by WordPress