new feature in trunk: services

14 views
Skip to first unread message

mdipierro

unread,
Mar 6, 2009, 9:11:05 AM3/6/09
to web2py Web Framework
Has anybody tried this yet?

Please try this and send me comments:

from gluon.tools import Service

service=Service(globals())
@service.run
@service.json
@service.jsonrpc
@service.xmlrpc
@service.amfrpc
def f(a,b):
return a+b

@service.rss
def myfeed():
return dict
(title='title',link='link',description='description',created_on=request.now,
entries=[dict
(title='title',link='link',description='description',created_on=request.now])

def call():
return service()

USAGE:
http://..../app/default/call/run/f?a=3&b=4
http://...../app/default//call/run/f/3/4
http://...../app/default//call/json/f/3/4
etc etc
etc ...
http://..../app/default//call/rss/myfeed

Jim

unread,
Mar 7, 2009, 3:32:23 PM3/7/09
to web2py Web Framework
OK, I'm a newbie. I'd like to use something like this, especially
after wrestling this morning trying to get the RSS example from the
manual working. Almost there but not quite. And using that example
would mean adding code to every single function

/application/controller/function/ [RSS] gets you the default
RSS feed for this function

/application/controller/function/arg1/arg2/ [ RSS] More detailed
feed

/application/controller/function/arg1/arg2/?color=red&object=widgets
[RSS] Extremely detailed

/application/controller/ [RSS] very broad feed

/application/ [RSS] incredibly broad - basically used by search
engines

Maybe that's possible with the way this is laid out.

Can you explain more about how that would work?

Fran

unread,
Mar 8, 2009, 8:32:59 AM3/8/09
to web2py Web Framework
mdipierro wrote:
> Has anybody tried this yet?

Looks very promising, but I must confess that I don't understand how
to use it.
I put it all into a test controller & it runs but I don't see how to
get this to work with my data.
- just returns 34 or "34" currently, which doesn't mean anything...
What are the 'a' & 'b' supposed to be?

F

mdipierro

unread,
Mar 8, 2009, 11:48:39 AM3/8/09
to web2py Web Framework
In the example you are exposing a function

def f(a,b): return a+b

which sums a and b. There is nothing special about a and b.
You can expose any function with takes any parameters you like.
Once you create a function you just decorate it with

@service.json

if you want to reurn its value as json, or with

@service.jsonrpc

if you want to be able to call it via json rpc. etc etc.

Fran

unread,
Mar 8, 2009, 12:46:53 PM3/8/09
to web2py Web Framework
On Mar 8, 3:48 pm, mdipierro <mdipie...@cs.depaul.edu> wrote:
> In the example you are exposing a function
> def f(a,b): return a+b
> which sums a and b. There is nothing special about a and b.
> You can expose any function with takes any parameters you like.

ok

So this should probably go in the model:
from gluon.tools import Service
service=Service(globals())

> Once you create a function you just decorate it with
> @service.json
> if you want to reurn its value as json, or with

Currently easy enough to download data as JSON using the .json()
syntax, e.g.:
item=db(table.id==t2.id).select(table.ALL).json()
return dict(item=item)

Does this do anything else?

This doesn't handle JSON upload at all does it?

> @service.jsonrpc
> if you want to be able to call it via json rpc. etc etc.

ok, so being able to easily expose controller functions to JSONRPC or
XMLRPC sounds *great*
Can these use the integrated Auth?
Anyone able to provide a way of testing this out at all?

Thanks,
F

mdipierro

unread,
Mar 8, 2009, 1:31:03 PM3/8/09
to web2py Web Framework


On Mar 8, 11:46 am, Fran <francisb...@googlemail.com> wrote:
> On Mar 8, 3:48 pm, mdipierro <mdipie...@cs.depaul.edu> wrote:
>
> > In the example you are exposing a function
> > def f(a,b): return a+b
> > which sums a and b. There is nothing special about a and b.
> > You can expose any function with takes any parameters you like.
>
> ok
>
> So this should probably go in the model:
> from gluon.tools import Service
> service=Service(globals())
>
> > Once you create a function you just decorate it with
> > @service.json
> > if you want to reurn its value as json, or with
>
> Currently easy enough to download data as JSON using the .json()
> syntax, e.g.:
> item=db(table.id==t2.id).select(table.ALL).json()
> return dict(item=item)
>
> Does this do anything else?

No but it allows you to define a function once and expose any multiple
services.

> This doesn't handle JSON upload at all does it?

I think it does. Can you provide an example of what you mean?

> > @service.jsonrpc
> > if you want to be able to call it via json rpc. etc etc.
>
> ok, so being able to easily expose controller functions to JSONRPC or
> XMLRPC sounds *great*
> Can these use the integrated Auth?

Yes can can use auth, but they cannot use auth decorators (I can make
it so).

> Anyone able to provide a way of testing this out at all?

I will rewrite the pyjamas examples to use this as soon as we ship
1.58.

Massimo

mdipierro

unread,
Mar 8, 2009, 1:32:30 PM3/8/09
to web2py Web Framework
correction. auth decorators do work

Fran

unread,
Mar 8, 2009, 2:55:25 PM3/8/09
to web2py Web Framework
On Mar 8, 5:31 pm, mdipierro <mdipie...@cs.depaul.edu> wrote:
> > This doesn't handle JSON upload at all does it?
> I think it does. Can you provide an example of what you mean?

What I'm trying to do is to upload data into my Web2Py application's
database from JavaScript.
Ideally this would be to the forms created by Crud (since this handles
validation).
I'm not sure this is possible though?
- e.g. do I have to be able to provide the hidden _formkey var?

I see that the forms use POST & multipart/form-data.
So using jQuery-1.3.2 I'm trying (http://docs.jquery.com/Ajax/
jQuery.ajax#options):
$.ajax({ type: "POST", contentType: "multipart/form-data",
url: "{{=URL
(r=request,c='cr',f='shelter',args='create')}}",
data: { name: "MyShelter", _formname:
"cr_shelter" }
});

This gives me:
Traceback (most recent call last):
File "C:\Bin\web2py\gluon\main.py", line 269, in wsgibase
environ=environ, keep_blank_values=1)
File "c:\bin\python25\lib\cgi.py", line 534, in __init__
self.read_multi(environ, keep_blank_values, strict_parsing)
File "c:\bin\python25\lib\cgi.py", line 650, in read_multi
raise ValueError, 'Invalid boundary in multipart form: %r' % (ib,)
ValueError: Invalid boundary in multipart form: ''

Not sure if this is a Web2Py or jQuery issue.

I've also been experimenting with Curl, but that requires me to save
the session in a cookie (OK) & the submit button doesn't have a name
to reference it (http://curl.haxx.se/docs/httpscripting.html)


Since I've been having problems with the Crud forms, I have developed
a custom controller function, which now requires me to reimplement all
the validation myself....since this is being done within a generic
CRUD controller, I'm not sure if I can get all the requires statements
from the model unless I store them inside a Storage() global variable?


Any help very much welcomed :)

F

Fran

unread,
Mar 8, 2009, 3:04:34 PM3/8/09
to web2py Web Framework
On Mar 8, 6:55 pm, Fran <francisb...@googlemail.com> wrote:
> I'm not sure if I can get all the requires statements
> from the model unless I store them inside a Storage() global variable?

They already are of course ;)

OK, looks like I'll be able to get my creates/updates from Javascript
working :)

What I'm still interested in frm this thread is how to test that the
functions I expose via XMLRPC/JSONRPC are working properly?
- including testing the authentication.

Is there any simple Web services client I can test from?
- another Web2Py appliance would be best I guess :)

F

mdipierro

unread,
Mar 8, 2009, 3:27:17 PM3/8/09
to web2py Web Framework
This is a jquery issue. Look into applications/admin/static/
ajax_edit.js

mdipierro

unread,
Mar 8, 2009, 3:32:21 PM3/8/09
to web2py Web Framework
Try this default.py

from gluon.tools import Service
service=Service(globals())
@service.xmlrpc
def add(a,b):
return a+b
@service.xmlrpc
def sub(a,b):
return a-b
def call():
return service()

and this from a python shell

import xmlrpclib
server=xmlrpclib.ServerProxy('http://hostname:port/app/call/
xmlrpc')
print server.add(3,4)
print server.sub(3,4)

For jsonrpc you can use the pyjamas example posted on applicances but
no it does not need anymore the xmlrpc.py model in there.

Massimo

Fran

unread,
Mar 8, 2009, 4:44:31 PM3/8/09
to web2py Web Framework
On Mar 8, 7:32 pm, mdipierro <mdipie...@cs.depaul.edu> wrote:
> Try this default.py

Thanks:

>>> server=xmlrpclib.ServerProxy('http://127.0.0.1:8000/welcome/call/xmlrpc')
>>> print server.add(3,4)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "c:\bin\python25\lib\xmlrpclib.py", line 1147, in __call__
return self.__send(self.__name, args)
File "c:\bin\python25\lib\xmlrpclib.py", line 1437, in __request
verbose=self.__verbose
File "c:\bin\python25\lib\xmlrpclib.py", line 1191, in request
headers
ProtocolError: <ProtocolError for 127.0.0.1:8000/welcome/call/xmlrpc:
400 BAD REQUEST>>
>>> server=xmlrpclib.ServerProxy('http://127.0.0.1:8000/welcome/default/call/xmlrpc')
>>> print server.add(3,4)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "c:\bin\python25\lib\xmlrpclib.py", line 1147, in __call__
return self.__send(self.__name, args)
File "c:\bin\python25\lib\xmlrpclib.py", line 1437, in __request
verbose=self.__verbose
File "c:\bin\python25\lib\xmlrpclib.py", line 1201, in request
return self._parse_response(h.getfile(), sock)
File "c:\bin\python25\lib\xmlrpclib.py", line 1340, in
_parse_response
return u.close()
File "c:\bin\python25\lib\xmlrpclib.py", line 785, in close
raise ResponseError()
ResponseError: ResponseError()

Trying same URL via the web browser:
Traceback (most recent call last):
File "C:\Bin\web2py\gluon\restricted.py", line 98, in restricted
exec ccode in environment
File "C:/Bin/web2py/applications/welcome/controllers/default.py",
line 26, in <module>
File "C:\Bin\web2py\gluon\globals.py", line 75, in <lambda>
self._caller = lambda f: f()
File "C:/Bin/web2py/applications/welcome/controllers/default.py",
line 24, in call
return service()
File "C:\Bin\web2py\gluon\tools.py", line 1704, in __call__
return self.serve_xmlrpc()
File "C:\Bin\web2py\gluon\tools.py", line 1646, in serve_xmlrpc
services = xmlrpc_services.values()
NameError: global name 'xmlrpc_services' is not defined

F

Fran

unread,
Mar 8, 2009, 5:15:55 PM3/8/09
to web2py Web Framework
On Mar 8, 7:27 pm, mdipierro <mdipie...@cs.depaul.edu> wrote:
>> ValueError: Invalid boundary in multipart form: ''
> This is a jquery issue. Look into applications/admin/static/
> ajax_edit.js

I see - need to define any old string as boundary, so:
$.ajax({
type: "POST",
contentType: 'multipart/form-data;boundary="MyBoundaryString"',
url: "{{=URL(r=request,c='cr',f='shelter',args=['create'])}}",
data: { name: "MyShelter", _formname: "cr_shelter" },
})

Doesn't give me the traceback, but the data isn't saved in the DB.
I'm assuming this is because I don't specify a _formkey?

F

Fran

unread,
Mar 8, 2009, 5:57:59 PM3/8/09
to web2py Web Framework
On Mar 6, 2:11 pm, mdipierro <mdipie...@cs.depaul.edu> wrote:
> Please try this and send me comments:
> from gluon.tools import Service
> service=Service(globals())
> @service.rss
> def myfeed():
>     return dict
> (title='title',link='link',description='description',created_on=request.now,
>                 entries=[dict
> (title='title',link='link',description='description',created_on=request.now])
> def call():
>     return service()
> USAGE:
>    http://..../app/default//call/rss/myfeed

This would be good to get more understanding of how to use as well.

Ideally I'd be able to call the RSS functionality from within my own
CRUD controller, so if my format=rss, I can:
return service.rss(db.table)
or similar...I don't suppose this can be made that easy? ;)
At least if I could do something like:
for i in db(db.table.id>0).count():
entries[i]=dict(title=db.table.name,link=URL
(r=request,c='default',f='data',args=
['read',db.table,db.table.id]),description=db.table.description,created_on=db.table.created_on)

F

mdipierro

unread,
Mar 8, 2009, 11:05:57 PM3/8/09
to web2py Web Framework
My bad. uploaded an old version. Uploading the most updated version in
trunk now.
Reply all
Reply to author
Forward
0 new messages