Login Register

Remote Procedure Call (RPC)

Dojo provides low level I/O out of the box, but as applications grow in complexity it's natural to want something less one-off-ish. Dojo's Remote Procedure Calls (RPC) module aims to make this process less error prone, easier, and require less code.

Remote Procedure Calls allows you to invoke a method on a remote host. Dojo provides a basic RPC client class that has been extended to provide access to JSON-RPC services and Yahoo services. It was designed so that it is easy to implement custom RPC services.

For example, you have a little application that you want to use to make some server calls. For simplicity, the methods you want the server to do are add(x,y) and subtract(x,y). Without using anything special, like an RPC client, you could do something like this:

add = function(x,y) {
        request = {x: x, y: y};
        dojo.xhrGet({
            url: "add.php",
            load: onAddResults,
            handleAs: "text",
                content: request
        });
}
subtract = function(x,y) {
        request = {x: x, y: y};
       
        dojo.xhrGet({
            url: "subtract",
            load: onSubtractResults,
            handleAs: "text"
                content: request
        });
}

This isn't particularly difficult but it is repetitive and error prone. Dojo's RPC clients simplify this process by taking a simple definition of the remote methods and application needs and generating client side functions to call these methods. You need only write this definition, and initialize an RPC client object and then all of these remote methods are available for you to use as normal.

The definition file, called a Simple Method Description (SMD) file, is a simple JSON string that defines a URL to process the RPC requests, any methods available at that URL, and the parameters those methods take. The definition for the example above might look like this:

{
        "serviceType": "JSON-RPC",
        "serviceURL": "rpcProcessor.php",
        "methods":[
                {
                        "name": "add",
                        "parameters":[
                                {"name": "x"},
                                {"name": "y"}   
                        ]
                },
                {
                        "name": "subtract",
                        "parameters":[
                                {"name": "x"},
                                {"name": "y"}   
                        ]
                }
        ]
}

Once the definition has been created, the code is pretty simple. The definition can be supplied either as a URL to retrieve it, a JSON string, or a JavaScript object, as shown in the following example.

var myObject = new dojo.rpc.JsonService("http://localhost/definition.smd");
var myObject = new dojo.rpc.JsonService({smdStr: definitionJSON});
var myObject = new dojo.rpc.JsonService(definitionObj);

Thats it! Now all that's left is to call the method as shown in the following example.

myObject.add(3,5);

Of course this just calls the method and doesn't address what is returned from the call or how to get at the results. Just like the rest of the I/O system in dojo 0.9+, the RPC system returns a deferred to which you can attach callbacks.

var myDeferred = myObject.add(3,5);
myDeferred.addCallback(myCallbackMethod);

Or, it could be more succinctly done this way:

var myDeferred = myObject.add(3,5).addCallback(myCallbackMethod);

You just add myCallbackMethod as a callback for the Deferred returned from myObject.add(). In this case myCallbackMethod is called with a parameter with a value of 8. Likewise, you can attach an errback method to the deferred object to process any errors returned from the server. You can add as many callbacks and errbacks to your deferred object as you want and they will be called in the order that they were connected to the deferred object.

In addition to JsonService, Dojo offers a JsonpService client, which is used for services such as Yahoo which provide JSON-P style service. Most services of this style can be represented in an SMD and passed to the JsonpService and used in the same fashion as above in a crossplatform manner. This makes mashups a cinch. Take a look in the dojox project at the Yahoo.smd example provide. Pass that url to JsonPService and all of Yahoo's services are at your finger tips and others are easy to add.

var svc = new dojo.rpc.JsonpService(dojo.moduleUrl("dojox.rpc", "yahoo.smd"), {appid: "dojoApp"});

The resulting Yahoo Service object allows you to perform web searches, do term extraction, and search all sorts of local an contextual data. See the SMD file for details on the available methods, parameters, and documentation pointers.

While Dojo is currently limited to these two RPC clients, the design of the base classes allows you to easily customize and extend dojo.rpc.RpcService to create services that meet your specific needs. Have a look at the source for RpcService.js and JsonService.js to see just how simple it is. If anyone is interested in contributing their own SMD files for their pet service or their company's services, please let us know!

Does not work with https:

 If I call a JSON service on a different web-server via https://..., I get:


name: "Error"


description: "bad http response code:12019"


message: "bad http response code:12019"


I suspect RPC is "hanging" on the Certificate Prompt.

uhm...

If you are calling a different host (not just domain) that is your problem... RPC uses IO.bind which uses XHR which is restricted by browsers with extreme security measures....

Support questions should be posted to the forums...

-Karl

What about the format of the response?

So if I'm writing my own services, do they response with JSON? If so, what does the response need to look like? That part of the documentation seems to be missing...

Writing the response

You can find a php example of the response code under:
dojo/tests/resources/testJsonRPCMediator.php

Copy that JSON.php file into your project and follow the testJsonRPCMediator.php example. The following code works for this example.

<?php
        chdir('../..');
        require 'config.php';
        require_once("core/util/JSON.php");
       
        header("Content-Type: text/json");

        class rpcClass {
                function add($x,$y) {
                        return $x + $y;
                }
        }

        $json = new Services_JSON;

        $results = array();
        $results['error'] = null;
       
        $jsonRequest = file_get_contents('php://input');

        $req = $json->decode($jsonRequest);
       
        $obj = new rpcClass();

        $method = $req->method;
       
        if ($method != "triggerRpcError") {
                $ret = call_user_func_array(array($obj,$method),$req->params);
                $results['result'] = $ret;
        } else {
                $results['error'] = "Triggered RPC Error";
        }
        $results['id'] = $req->id;

        $encoded = '/*'.$json->encode($results).'*/';

        print $encoded;
?>

Just simply modify the methods of the rpcClass to add or modify the rpc methods available.

PHP 5.2

That's very interesting! All the other classes I found so far require PHP 5.2 because they use the new json_encode and json_decode functions but this looks like it will work with 5.0! ( I know, it's very old. I wish I could upgrade...)

Thanks!