Code


Version 5 (modified by anonymous, 5 years ago) (diff)

--

JsonRpc

This is an easy-to-use implementation of a JSON-RPC handler for Django.

Features:



Example Django Usage

myproject/myapp/views.py:

from jsonrpc import JsonRpc, publicmethod

class MyRpcMethods(object):

    url = reverse("myapp-rpc")

    @publicmethod
    def add(x, y):
        return x+y

    @publicmethod
    def sub(x, y):
        return x-y

    def read_diary(self):
        return "Here's all my secrets ..."

    @publicmethod
    def find_person(attribs):

        filters = {}
        for key in attribs.keys():
            if key in ("first_name", "last_name"):
                filters[key] = attribs[key]

        return [
            {"first_name": p.first_name, "last_name": p.last_name}
            for p in Person.objects.filter(**filters)
        ]

def my_rpc_view(request):

    rpc     = JsonRpc( MyRpcMethods() )
    result  = rpc.handle_request(request)

    return result

Example Javascript client usage

var rpc = new dojo.rpc.JsonService("/myapp/rpc/");

rpc.add(3,4).addCallback(function(result) {
    console.log(result);
});
>>> 7

rpc.callRemote("sub", [9,5]).addCallback(function(result) {
    console.log(result);
});
>>> 4

rpc.callRemote("read_diary").addCallback(function(secrets) {
    console.log(secrets);
});
>>> no such method

rpc.find_person({last_name: "Baggins"}).addCallback(function(result) {
    dojo.forEach(result, function(person) {
      console.log("Found: " + person.first_name, person.last_name);
    });
});
>>> Found: Bilbo Baggins
>>> Found: Frodo Baggins

JsonRpc

jsonrpc.py

#
# Copyright (c) 2009, Ben Wilber (benwilber@gmail.com)
# All rights reserved
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License. You should have
# received a copy of the GPL license along with this program; if you
# did not, you can find it at http://www.gnu.org/
#

class publicmethod(object):

    def __init__(self, method):
        self.method = method
        __public__  = True

    def __call__(self, *args, **kwargs):
        return self.method(*args, **kwargs)

    def get_args(self):
        from inspect import getargspec
        return [ a for a in getargspec(self.method).args if (a != "self") ]

class JsonRpc(object):

    def __init__(self, instance, allow_errors=True, report_methods=True):

        self.instance            = instance
        self.allow_errors        = allow_errors
        self.report_methods        = report_methods

        if not hasattr(self.instance, "url"):
            raise Exception("'url' not present in supplied instance")

    def get_public_methods(self):

        return [
            m for m in dir(self.instance) if \
            (getattr(self.instance, m).__class__.__name__ == "publicmethod") and \
            (getattr(self.instance, m).__public__ == True)
        ]

    def generate_smd(self):

        self.smd = {
            "serviceType": "JSON-RPC",
            "serviceURL": self.instance.url,
            "methods": []
        }

        if self.report_methods:
            self.smd["methods"] += [
                {"name": method, "parameters": getattr(self.instance, method).get_args()} \
                for method in self.get_public_methods()
            ]

        return simplejson.dumps(self.smd)
 
    def dispatch(self, method, params):

        if hasattr(self.instance, "dispatch") and \
            callable(self.instance.dispatch):
            return self.instance.dispatch(method, params)
        elif method in self.get_public_methods():
            return getattr(self.instance, method)(*params)
        else:
            return "no such method"

    def serialize(self, raw_post_data):

        raw_request        = simplejson.loads(raw_post_data)
        request_id        = raw_request.get("id", 0)
        request_method    = raw_request.get("method")
        request_params    = raw_request.get("params", [])

        response        = {"id": request_id}

        try:
            response["result"] = self.dispatch(request_method, request_params)
        except:
            if self.allow_errors:
                from sys import exc_type, exc_value
                response["error"] = "%s: %s" % (exc_type, exc_value)
            else:
                response["error"] = "error"

        return simplejson.dumps(response)

    def handle_request(self, request):

        if request.method == "POST" and \
            len(request.POST) > 0:
            return self.serialize(request.raw_post_data)
        else:
            return self.generate_smd()