Re: Ajax with JSON-RPC -- new Django handler

2009-07-10 Thread djfis...@gmail.com

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

2009-07-10 Thread BenW

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

2009-07-09 Thread BenW

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

2009-06-19 Thread lkcl

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

2009-06-18 Thread lkcl



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

2009-06-18 Thread Adi Andreias

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

2009-06-04 Thread BenW

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

2009-06-04 Thread BenW

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

2009-06-04 Thread Artem Egorkine
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

2009-06-03 Thread BenW

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

2009-06-03 Thread Alex Gaynor
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

2009-06-03 Thread BenW

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
-~--~~~~--~~--~--~---