Re: Ajax with JSON-RPC -- new Django handler
According to the jsonrpc 1.1 working draft, the request type and response should be application/json not application/javascript. Even if you handle requests that are in other types for compatibility, you probably want your responses to be the correct type. http://json-rpc.org/wd/JSON-RPC-1-1-WD-20060807.html#RequestHeaders -David On Jul 10, 9:21 am, BenW wrote: > I fixed the above problem with URL reversing by refactoring the > JSONRPCService.__call__ method to grab it from the request object. > > def __call__(self, request, extra=None): > > if request.method == "POST": > return HttpResponse(self.process(request), > mimetype="application/javascript") > > url = request.get_full_path() > return HttpResponse(self.get_smd(url), > mimetype="application/javascript") > > This makes more sense since the service url was already defined in the > urlconf, so there's no point in redefining it just so that it can go > in the SMD. > > I also reworked the get_smd() method in JSONRPCServiceBase to take the > url parameter: > > def get_smd(self, url): > > smd = { > "serviceType": "JSON-RPC", > "serviceURL": url, > "methods": [] > } > > import inspect > for method in self.listmethods(): > sig = inspect.getargspec(self.methods[method]) > smd["methods"].append({ > "name": method, > "parameters": [ {"name": val} for val in sig.args if \ > val not in ("self", "request") ] > }) > > return simplejson.dumps(smd) > > It now defines the smd directly rather than it being defined in > __init__ then populated here. I also added a test to remove 'self' > and 'request' from the reported method parameters since those are > internal and having them reported will cause an RPC client that > imports the remote methods into their namespace (as was discussed in > previous post) to throw errors. > > Purely for my own needs, I added an optional param to > JSONRPCServiceBase.__init__: > > def __init__(self, auth_method=None) > self.auth_method = auth_method > > in JSONRPCServiceBase I fixed up process() to call the auth_method (if > it was defined) to determine if the remote client is allowed to call > that method: > > def process(self, request): > > data = simplejson.loads(request.raw_post_data) > id, method, params = data["id"], data["method"], data > ["params"] > > if self.auth_method: > answer = self.auth_method(request, method, params) > try: > answer, message = answer > except TypeError: > message = "not authorized" > > if not answer: > return self.error(id, 100, message) > > ... > > You can use it like so: > > def adminrpc_auth(request, method, params): > > return request.session.user.is_admin > > adminrpc = JSONRPCService(auth_method=adminrpc_auth) > > @jsonremote(adminrpc) > def save_realm(request, realm_obj): > > return realm_obj > > This way if you have a collection of methods that should only be > available to an admin user, you can test that in one place rather than > in every method. The auth_method can optionally return a custom error > message: > > return request.session.user.is_admin, "Admins Only" > > The default is just "not authorized" -- I'll post my complete mods on > the wiki later. > > Any opinions on my modifications are welcome! > > Thanks, > > Ben --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups "Django users" group. To post to this group, send email to django-users@googlegroups.com To unsubscribe from this group, send email to django-users+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/django-users?hl=en -~--~~~~--~~--~--~---
Re: Ajax with JSON-RPC -- new Django handler
I fixed the above problem with URL reversing by refactoring the JSONRPCService.__call__ method to grab it from the request object. def __call__(self, request, extra=None): if request.method == "POST": return HttpResponse(self.process(request), mimetype="application/javascript") url = request.get_full_path() return HttpResponse(self.get_smd(url), mimetype="application/javascript") This makes more sense since the service url was already defined in the urlconf, so there's no point in redefining it just so that it can go in the SMD. I also reworked the get_smd() method in JSONRPCServiceBase to take the url parameter: def get_smd(self, url): smd = { "serviceType": "JSON-RPC", "serviceURL": url, "methods": [] } import inspect for method in self.listmethods(): sig = inspect.getargspec(self.methods[method]) smd["methods"].append({ "name": method, "parameters": [ {"name": val} for val in sig.args if \ val not in ("self", "request") ] }) return simplejson.dumps(smd) It now defines the smd directly rather than it being defined in __init__ then populated here. I also added a test to remove 'self' and 'request' from the reported method parameters since those are internal and having them reported will cause an RPC client that imports the remote methods into their namespace (as was discussed in previous post) to throw errors. Purely for my own needs, I added an optional param to JSONRPCServiceBase.__init__: def __init__(self, auth_method=None) self.auth_method = auth_method in JSONRPCServiceBase I fixed up process() to call the auth_method (if it was defined) to determine if the remote client is allowed to call that method: def process(self, request): data = simplejson.loads(request.raw_post_data) id, method, params = data["id"], data["method"], data ["params"] if self.auth_method: answer = self.auth_method(request, method, params) try: answer, message = answer except TypeError: message = "not authorized" if not answer: return self.error(id, 100, message) ... You can use it like so: def adminrpc_auth(request, method, params): return request.session.user.is_admin adminrpc = JSONRPCService(auth_method=adminrpc_auth) @jsonremote(adminrpc) def save_realm(request, realm_obj): return realm_obj This way if you have a collection of methods that should only be available to an admin user, you can test that in one place rather than in every method. The auth_method can optionally return a custom error message: return request.session.user.is_admin, "Admins Only" The default is just "not authorized" -- I'll post my complete mods on the wiki later. Any opinions on my modifications are welcome! Thanks, Ben --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups "Django users" group. To post to this group, send email to django-users@googlegroups.com To unsubscribe from this group, send email to django-users+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/django-users?hl=en -~--~~~~--~~--~--~---
Re: Ajax with JSON-RPC -- new Django handler
Sorry for digging up this thread but I fell off the list a bit and just checked back today. I really like the Pyjamas jsonprc implementation. In fact, I like it so much I've gone ahead and modified a few things to do the SMD generation and service URL resolution. However, I have a problem with my approach. This is how I modified JSONRPCServiceBase.__init__: def __init__(self, url): self.methods = {} self.smd = { "serviceType": "JSON-RPC", "serviceURL": url, "methods": [] } Notice that I added the 'url' param and the smd skeleton (no methods yet) I then added the method 'get_smd()' to JSONRPCServiceBase: def get_smd(self): import inspect for method in self.listmethods(): sig = inspect.getargspec(self.methods[method]) self.smd["methods"].append({ "name": method, "parameters": [ {"name": val} for val in sig.args ] }) return simplejson.dumps(self.smd) Then I fixed up JSONRPCService.__call__: def __call__(self, request, extra=None): if request.method == "POST": return HttpResponse(self.process(request), mimetype="application/javascript") else: return HttpResponse(self.get_smd(), mimetype="application/javascript") Use it like so: from jsonrpc import JSONRPCService, jsonremote chatservice = JSONRPCService("/chat/") @jsonremote(chatservice): def send_message(request, message): do something ... Having GET requests return the SMD allows client apps to resolve the methods before calling them so you don't have to use a str-ified version: var chat_service = new dojo.rpc.JsonService("/chat/"); chat_service.send_message("Hello World!").addCallback(function (response) { console.log(response); }); vs: var chat_service = new dojo.rpc.JsonService(); chat_service.serviceUrl = "/chat/"; chat_service.callRemote("send_message", ["Hello World"]).addCallback (function(response) { console.log(response); }); Now the problem ... I can't get URL reversing to work when first setting up the service: from jsonrpc import JSONRPCService, jsonremote chatservice = JSONRPCService( reverse("chat-rpc") ) Urlconf: url(r"^chat/$", "myproj.myapp.views.chatservice", name="chat-rpc", ), ViewDoesNotExist: Tried chatservice in module myproj.myapp.views. Error was: 'module' object has no attribute 'chatservice' But just sticking "/chat/" in there works great. This has to do with when the url is actually reversed -- but I can't figure it out. Any help would be great. Thanks, Ben On Jun 19, 1:17 am, lkcl wrote: > ok, i added a copy of the code to the wiki page, as some people may > find that easier to access and evaluate rather than from some other > random google group page. > l. --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups "Django users" group. To post to this group, send email to django-users@googlegroups.com To unsubscribe from this group, send email to django-users+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/django-users?hl=en -~--~~~~--~~--~--~---
Re: Ajax with JSON-RPC -- new Django handler
ok, i added a copy of the code to the wiki page, as some people may find that easier to access and evaluate rather than from some other random google group page. l. --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups "Django users" group. To post to this group, send email to django-users@googlegroups.com To unsubscribe from this group, send email to django-users+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/django-users?hl=en -~--~~~~--~~--~--~---
Re: Ajax with JSON-RPC -- new Django handler
On Jun 3, 5:14 pm, BenW wrote: > I just posted a JSON-RPC handler I've been working with on the wiki: > > http://code.djangoproject.com/wiki/Jsonrpc > > I'd be interested in feedback from anyone doing async javascript with > Django over RPC. ben, hi, there are many jsonrpc implementations. the best one i've found was best modified by pimentech.fr and makes use of __call__ and decorators, and makes it unbelievably simple to turn functions in a module, or functions in a class, into a JSONRPC service. JSONRPC is like the bedrock of pyjamas web 2.0 applications, and django is the framework i use so i recommend it a _lot_. so, i've made sure that the JSONRPC linkage between the two is the easiest possible one i can find. comparing the two implementations - see jsonrpc.py at: http://groups.google.com/group/pyjamas-dev/files [STOP at line 79 - ignore the FormsProcessor class] the implementation you've written seems... clunky, by comparison. there is an elegance to the jsonrpc.py that we're using. you should have seen it before error handling and comments were added: it fitted into about 35 lines of code! but, error handling and traceback reports some people considered important enough to actually kick them back to the web 2.0 application for display on-screen during development, so the exception handling someone contributed (i think someone on web2py group). usage is utterly, utterly trivial: from jsonrpc import jsonservice, jsonremote jsonservice = JSONRPCService() @jsonremote(jsonservice) def test(request, echo_param): return "echoing the param back: %s", echo_param @jsonremote(jsonservice) def add(request, x, y): return x+y save that in a file djangoapp/views.py - then you hand the jsonservice instance to the urlpatterns: (r'^service1/$', 'djangoapp.views.jsonservice'), you can of course put @jsonremote(jsonservice) onto class methods as well (i've never done that, preferring to design the module with global functions, which are typically self-contained anyway, and the use of a class is actually less efficient for no real gain). one advantage of having the "request" parameter handed in is this: the function is otherwise IDENTICAL to a quotes standard quotes django view function. i've often converted "standard" django views over to JSONRPC services with little effort required. there are other advantages to passing in the initial "request" object, such as being able to determine the IP address of the caller; access to cookies etc. inside the JSONRPC function. for things like session info - logins etc. - this is absolutely essential. i do particularly like the report_smd() function that you've added, btw. many people use GET on JSONRPC services and go "huh??" :) also you (and others) may find this to be useful: http://lkcl.net/jsonrpclib.tgz it's a modified version of matt harrison's jsonrpclib code, which he originally took from xmlrpclib. i've added error handling and tidied it up a bit, and now use it to do unit tests on JSONRPC services. one of the problems with web 2.0 development is that you're never sure if the browser's buggered or your code is. or maybe the framework. or you got the URL wrong. or you didn't understand XSS AJAX security restrictions. having a python jsonrpc client helps eliminate many of the things that could be wrong. i'll be emphasising and talking about this in the pyjamas + django tutorial at europython, if anyone's interested / attending. l. l. --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups "Django users" group. To post to this group, send email to django-users@googlegroups.com To unsubscribe from this group, send email to django-users+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/django-users?hl=en -~--~~~~--~~--~--~---
Re: Ajax with JSON-RPC -- new Django handler
This module could be useful, but there are all sort of problems in code. Like, __public__ = True you meant: self.__public__ = True ? After fixing that I get: AttributeError: 'tuple' object has no attribute 'args' on line return [ a for a in getargspec(self.method).args if (a != "self") ] This could be a version dependent problem ... or code was just not tested? And AFAIK, in Python code style guidelines assignment operator shouldn't be spaced like this: self.instance= instance I'll need to do some fixes and tweaks before using it, but thanks for contributing. On Jun 4, 8:43 pm, BenW wrote: > I made a few changes to make it a bit more general-purpose. It now > uses @publicmethod instead of the horrific public__ notation. > However, the dispatcher class just checks if method.__class__.__name__ > == 'publicmethod' and __public__ == True inside it. > > This seems a bit odd but I'm not sure how to make it cleaner. > Suggestions are welcome! > > Thanks, > > Ben > > On Jun 4, 7:47 am, BenW wrote: > > > > > Ahh yes, I had not considered calling them from Python since in my use > > case they are treated more like an extension into the browser than > > anything else. I will definitely refactor the class to use > > @publicmethod so as to make the instance containing RPC methods more > > general-purpose. > > > Thanks for the input! > > > Ben > > > On Jun 4, 12:02 am, Artem Egorkine wrote: > > > > On Wed, Jun 3, 2009 at 9:18 PM, BenW wrote: > > > > > Sorry about the example having bad syntax (doh!) -- I will get that > > > > fixed. I chose the public__ prefix because it makes it easier to > > > > introspect the supplied instance to find the methods intended to be > > > > public without forcing users of the class to provide a list > > > > themselves. You can put the class anywhere you want, I just stuck it > > > > in the view to keep it all together in the view. The RPC methods > > > > defined in that class are only used in that view. > > > > > And certainly the public__ prefix isn't any more unnatural than the > > > > ORM's query syntax. > > > > In your programming experience where, how many times have you found > > > yourself > > > reshuffling methods and making them public or private when refactoring the > > > API? Now imagine that you have methods calling other methods and you made > > > one of them public or private. You will now need to look up all references > > > to it and rename those calls as well... > > > > - Artem --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups "Django users" group. To post to this group, send email to django-users@googlegroups.com To unsubscribe from this group, send email to django-users+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/django-users?hl=en -~--~~~~--~~--~--~---
Re: Ajax with JSON-RPC -- new Django handler
I made a few changes to make it a bit more general-purpose. It now uses @publicmethod instead of the horrific public__ notation. However, the dispatcher class just checks if method.__class__.__name__ == 'publicmethod' and __public__ == True inside it. This seems a bit odd but I'm not sure how to make it cleaner. Suggestions are welcome! Thanks, Ben On Jun 4, 7:47 am, BenW wrote: > Ahh yes, I had not considered calling them from Python since in my use > case they are treated more like an extension into the browser than > anything else. I will definitely refactor the class to use > @publicmethod so as to make the instance containing RPC methods more > general-purpose. > > Thanks for the input! > > Ben > > On Jun 4, 12:02 am, Artem Egorkine wrote: > > > On Wed, Jun 3, 2009 at 9:18 PM, BenW wrote: > > > > Sorry about the example having bad syntax (doh!) -- I will get that > > > fixed. I chose the public__ prefix because it makes it easier to > > > introspect the supplied instance to find the methods intended to be > > > public without forcing users of the class to provide a list > > > themselves. You can put the class anywhere you want, I just stuck it > > > in the view to keep it all together in the view. The RPC methods > > > defined in that class are only used in that view. > > > > And certainly the public__ prefix isn't any more unnatural than the > > > ORM's query syntax. > > > In your programming experience where, how many times have you found yourself > > reshuffling methods and making them public or private when refactoring the > > API? Now imagine that you have methods calling other methods and you made > > one of them public or private. You will now need to look up all references > > to it and rename those calls as well... > > > - Artem --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups "Django users" group. To post to this group, send email to django-users@googlegroups.com To unsubscribe from this group, send email to django-users+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/django-users?hl=en -~--~~~~--~~--~--~---
Re: Ajax with JSON-RPC -- new Django handler
Ahh yes, I had not considered calling them from Python since in my use case they are treated more like an extension into the browser than anything else. I will definitely refactor the class to use @publicmethod so as to make the instance containing RPC methods more general-purpose. Thanks for the input! Ben On Jun 4, 12:02 am, Artem Egorkine wrote: > On Wed, Jun 3, 2009 at 9:18 PM, BenW wrote: > > > Sorry about the example having bad syntax (doh!) -- I will get that > > fixed. I chose the public__ prefix because it makes it easier to > > introspect the supplied instance to find the methods intended to be > > public without forcing users of the class to provide a list > > themselves. You can put the class anywhere you want, I just stuck it > > in the view to keep it all together in the view. The RPC methods > > defined in that class are only used in that view. > > > And certainly the public__ prefix isn't any more unnatural than the > > ORM's query syntax. > > In your programming experience where, how many times have you found yourself > reshuffling methods and making them public or private when refactoring the > API? Now imagine that you have methods calling other methods and you made > one of them public or private. You will now need to look up all references > to it and rename those calls as well... > > - Artem --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups "Django users" group. To post to this group, send email to django-users@googlegroups.com To unsubscribe from this group, send email to django-users+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/django-users?hl=en -~--~~~~--~~--~--~---
Re: Ajax with JSON-RPC -- new Django handler
On Wed, Jun 3, 2009 at 9:18 PM, BenW wrote: > > Sorry about the example having bad syntax (doh!) -- I will get that > fixed. I chose the public__ prefix because it makes it easier to > introspect the supplied instance to find the methods intended to be > public without forcing users of the class to provide a list > themselves. You can put the class anywhere you want, I just stuck it > in the view to keep it all together in the view. The RPC methods > defined in that class are only used in that view. > > And certainly the public__ prefix isn't any more unnatural than the > ORM's query syntax. > In your programming experience where, how many times have you found yourself reshuffling methods and making them public or private when refactoring the API? Now imagine that you have methods calling other methods and you made one of them public or private. You will now need to look up all references to it and rename those calls as well... - Artem --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups "Django users" group. To post to this group, send email to django-users@googlegroups.com To unsubscribe from this group, send email to django-users+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/django-users?hl=en -~--~~~~--~~--~--~---
Re: Ajax with JSON-RPC -- new Django handler
Sorry about the example having bad syntax (doh!) -- I will get that fixed. I chose the public__ prefix because it makes it easier to introspect the supplied instance to find the methods intended to be public without forcing users of the class to provide a list themselves. You can put the class anywhere you want, I just stuck it in the view to keep it all together in the view. The RPC methods defined in that class are only used in that view. And certainly the public__ prefix isn't any more unnatural than the ORM's query syntax. Ben On Jun 3, 10:33 am, Alex Gaynor wrote: > On Wed, Jun 3, 2009 at 12:14 PM, BenW wrote: > > > I just posted a JSON-RPC handler I've been working with on the wiki: > > >http://code.djangoproject.com/wiki/Jsonrpc > > > I'd be interested in feedback from anyone doing async javascript with > > Django over RPC. > > > Thanks! > > > Ben > > a) This code can't possibly do anything other than raise a SyntaxError, > you're missing the apporpriate def statements. > b) There is 0 reason to define the class inside of the method in this > instance. > c) the public__ notation is horrific, use a decorator or something. > > Alex > > -- > "I disapprove of what you say, but I will defend to the death your right to > say it." --Voltaire > "The people's good is the highest law."--Cicero --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups "Django users" group. To post to this group, send email to django-users@googlegroups.com To unsubscribe from this group, send email to django-users+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/django-users?hl=en -~--~~~~--~~--~--~---
Re: Ajax with JSON-RPC -- new Django handler
On Wed, Jun 3, 2009 at 12:14 PM, BenW wrote: > > I just posted a JSON-RPC handler I've been working with on the wiki: > > http://code.djangoproject.com/wiki/Jsonrpc > > I'd be interested in feedback from anyone doing async javascript with > Django over RPC. > > Thanks! > > Ben > > > > a) This code can't possibly do anything other than raise a SyntaxError, you're missing the apporpriate def statements. b) There is 0 reason to define the class inside of the method in this instance. c) the public__ notation is horrific, use a decorator or something. Alex -- "I disapprove of what you say, but I will defend to the death your right to say it." --Voltaire "The people's good is the highest law."--Cicero --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups "Django users" group. To post to this group, send email to django-users@googlegroups.com To unsubscribe from this group, send email to django-users+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/django-users?hl=en -~--~~~~--~~--~--~---
Ajax with JSON-RPC -- new Django handler
I just posted a JSON-RPC handler I've been working with on the wiki: http://code.djangoproject.com/wiki/Jsonrpc I'd be interested in feedback from anyone doing async javascript with Django over RPC. Thanks! Ben --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups "Django users" group. To post to this group, send email to django-users@googlegroups.com To unsubscribe from this group, send email to django-users+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/django-users?hl=en -~--~~~~--~~--~--~---