JSON Remote Procedure Calls

By now, you may have noticed that even after using Dojo's various XHR methods such as dojo.xhrGet to reduce boilerplate, it is still a somewhat redundant and error-prone operation to repeatedly provide content to the call and write a load callback function. Fortunately, you can use Dojo's RPC (Remote Procedure Call) machinery to mitigate some of the monotony via Core's dojo.rpc module. In short, you provide some configuration information via a Simple Method Description (SMD), create an instance of this service by passing in the configuration, and then use the service instead of the xhrGet et al. If your application has a fairly standard way of interacting with the server and responds in very similar ways for error handling, etc., the benefit of using the rpc module is that you'll generally have a cleaner design that's less error-prone.

Currently, Core provides a JsonService and a JsonpService, which both descend from a base class called RpcService.

Tip

The dojox.rpc module provides additional RPC capabilities, some of which may soon be migrated to Core.

JSON RPC Example

To illustrate some basic usage of the RPC machinery, let's work through an example that uses JsonService to process a list of numbers, providing the sum of the numbers or the sum of the sum of each number squared. The client consists of an SMD that provides two methods, sum and sumOfSquares, which both take a list of numbers:

<html>
    <head>
        <title>Fun with JSON RPC!</title>

        <script type="text/javascript"
            src="http://o.aolcdn.com/dojo/1.1/dojo/dojo.xd.js"
            djConfig="isDebug:true">
        </script>
        <script type="text/javascript">
            dojo.require("dojo.rpc.JsonService");
            dojo.addOnLoad(function(  ) {

                //construct the smd as an Object literal...
                var o = {
                    "serviceType": "JSON-RPC",
                    "serviceURL": "/",
                    "methods":[
                        {
                            "name": "sum",
                            "parameters":[{name : "list"}]
                        },
                        {
                            "name": "sumOfSquares",
                           "parameters":[{name : "list"}]
                        }
                    ]
                }

                //instantiate the service
                var rpcObject = new dojo.rpc.JsonService(o);

                //call the service and use the Deferred that is returned to
add a callback
                var sum = rpcObject.sum([4,8,15,16,23,42]);
                sum.addCallback(function(response) {
                    console.log("the answer is ", response);
                });
                //add more callbacks, errbacks, etc.

                //call sumOfSquares the very same way...
            });
        </script>
        <body>
    </body>
</html>

Hopefully, you see the connection that if there were lots of methods communicating with the server in a very standardized way, the general simplicity of calling an RPC client once you've set it up initially declutters the design significantly. Much of the elegance in using the dojo.rpc.JsonService is that it returns a Deferred so you can add callbacks and errbacks as needed.

In case you'd like to interact with the example, here's an example service script. For simplicity, this script purposely doesn't bring in a JSON processing library, but you'd most certainly want to do that for anything much more complicated than this example:

import cherrypy
import os
# a foo.html file will contain our Dojo code performing the XHR request
# and that's all the following config directive is doing

current_dir = os.getcwd()
config = {'/foo.html' :
    {
    'tools.staticfile.on' : True,
    'tools.staticfile.filename' : os.path.join(current_dir, 'foo.html')
    }
}

class Content:

    @cherrypy.expose
    def index(self):
        #############################################################
        # for sheer simplicity, this example does not use a json lib.
        # for anything more sophisticated than this example,
        # get a good json library from http://json.org
        ############################################################

        # read the raw POST data
        rawPost = cherrypy.request.body.read(  )

        # cast to object
        obj = eval(rawPost) #MAJOR security hole! you've been warned...

        # process the data
        if obj["method"] == "sum":
            result = sum(obj["params"][0])
        if obj["method"] == "sumOfSquares":
            result = sum([i*i for i in obj["params"][0]])

        # return a json response
        return str({"result" : result})

# start up the web server and have it listen on 8080
cherrypy.quickstart(Content(  ), '/', config=config)

Using the JsonpService is very similar to using the JsonService. In your Dojo installation, there is an example SMD file for Yahoo! services located at dojox/rpc/yahoo.smd if you want to try it out.

Get Dojo: The Definitive Guide now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.