``a_server = ServerProxy(location,transport=None,encoding=None,verbose=False,version=None)
``:code
The important arguments are:
- ``location`` is the remote URL for the server. There are examples below.
- ``verbose=True`` activates useful diagnostics
- ``version`` sets the jsonrpc version. It is ignored by jsonrpc. Set this to ``version='2.0'`` to support jsonrpc2. Because it is ignored by jsonrpc, setting it gains support for both versions. It is not supported by XMLRPC.
#### XMLRPC Libraries
There are XMLRPC libraries for many programming languages (including C, C++, Java, C#, Ruby, and Perl), and they can interoperate with each other. This is one the best methods to create applications that talk to each other independent of the programming language.
The XMLRPC client can also be implemented inside a web2py action, so that one action can talk to another web2py application (even within the same installation) using XMLRPC. Beware of session deadlocks in this case. If an action calls via XMLRPC a function in the same app, the caller must release the session lock before the call:
``
session.forget(response)
``:code
[[jsonrpc]] [[jsonrpc2]]
#### JSONRPC
``JSONRPC``:inxx
``JSONRPC2``:inxx
In this section we are going to use the same code example as for XMLRPC but we will expose the service using JSONRPC instead:
``
@service.jsonrpc
@service.jsonrpc2
def call(): return service()
``:code
Notice that it also possible to instantiate multiple service objects, register the same different functions with them, and expose some of them with authentication and some not:
``
public_service=Service()
private_service=Service()
@public_service.jsonrpc
@private_service.jsonrpc
def f(): return 'public'
@private_service.jsonrpc
def g(): return 'private'
def public_call(): return public_service()
@auth.requires_login()
def private_call(): return private_service()
``:code
+This assumes that the caller is passing credentials in the HTTP header (a valid session cookie or using [[basic authentication ../09/#basic_authentication]], as discussed in the previous chapter). The client must support it; not all clients do.
+
+If using ServerProxy() described above, you can pass basic authentication credentials in the URL, like so:
+``
+URL='http://user:password@127.0.0.1:8000/app/default/private_call/jsonrpc2'
+service = ServerProxy(URL, version='2.0')
+``:code
+
+where the function ``private_call`` in the controller is decorated for user authentication
+
+
``a_server = ServerProxy(location,transport=None,encoding=None,verbose=False,version=None)
``:code
The important arguments are:
- ``location`` is the remote URL for the server. There are examples below.
- ``verbose=True`` activates useful diagnostics
- ``version`` sets the jsonrpc version. It is ignored by jsonrpc. Set this to ``version='2.0'`` to support jsonrpc2. Because it is ignored by jsonrpc, setting it gains support for both versions. It is ignored by XMLRPC.
#### XMLRPC Libraries
There are XMLRPC libraries for many programming languages (including C, C++, Java, C#, Ruby, and Perl), and they can interoperate with each other. This is one the best methods to create applications that talk to each other independent of the programming language.
The XMLRPC client can also be implemented inside a web2py action, so that one action can talk to another web2py application (even within the same installation) using XMLRPC. Beware of session deadlocks in this case. If an action calls via XMLRPC a function in the same app, the caller must release the session lock before the call:
``
session.forget(response)
``:code
[[jsonrpc]] [[jsonrpc2]]
#### JSONRPC
``JSONRPC``:inxx
``JSONRPC2``:inxx
In this section we are going to use the same code example as for XMLRPC but we will expose the service using JSONRPC instead:
``
@service.jsonrpc
@service.jsonrpc2
def call(): return service()
``:code
Notice that it also possible to instantiate multiple service objects, register the same different functions with them, and expose some of them with authentication and some not:
``
public_service=Service()
private_service=Service()
@public_service.jsonrpc
@private_service.jsonrpc
def f(): return 'public'
@private_service.jsonrpc
def g(): return 'private'
def public_call(): return public_service()
@auth.requires_login()
def private_call(): return private_service()
``:code
-This assumes that the caller is passing credentials in the HTTP header (a valid session cookie or using basic authentication, as discussed in the previous section). The client must support it; not all clients do.

+#### ServerProxy signature
+
+``a_server = ServerProxy(location,transport=None,encoding=None,verbose=False,version=None)
+``:code
+The important arguments are:
+- ``location`` is the remote URL for the server. There are examples below.
+- ``verbose=True`` activates useful diagnostics
+- ``version`` sets the jsonrpc version. It is ignored by jsonrpc. Set this to ``version='2.0'`` to support jsonrpc2. Because it is ignored by jsonrpc, setting it gains support for both versions. It is ignored by XMLRPC.
+
+#### XMLRPC Libraries
+
There are XMLRPC libraries for many programming languages (including C, C++, Java, C#, Ruby, and Perl), and they can interoperate with each other. This is one the best methods to create applications that talk to each other independent of the programming language.
The XMLRPC client can also be implemented inside a web2py action, so that one action can talk to another web2py application (even within the same installation) using XMLRPC. Beware of session deadlocks in this case. If an action calls via XMLRPC a function in the same app, the caller must release the session lock before the call:
``
session.forget(response)
``:code
+[[jsonrpc]] [[jsonrpc2]]
#### JSONRPC
``JSONRPC``:inxx
+``JSONRPC2``:inxx
In this section we are going to use the same code example as for XMLRPC but we will expose the service using JSONRPC instead:
``
@service.jsonrpc
@service.jsonrpc2
def add(a,b):
return a+b
def call():
return service()
``:code
JSONRPC is very similar to XMLRPC but uses JSON instead of XML as data serialization protocol.
+#### Accessing JSONRPC services from web2py
+
Of course we can call the service from any program in any language but here we will do it in Python. web2py ships with a module "gluon/contrib/simplejsonrpc.py" created by Mariano Reingart. Here is an example of how to use to call the above service:
``
>>> from gluon.contrib.simplejsonrpc import ServerProxy
>>> URL = "http://127.0.0.1:8000/app/default/call/jsonrpc"
>>> service = ServerProxy(URL, verbose=True)
>>> print service.add(1, 2)
``:code
+Use "http://127.0.0.1:8000/app/default/call/jsonrpc2" for jsonrpc2,
+and create the service object like this:
+``
+service = ServerProxy(URL,verbose=True,version='2.0')
+``:code
There are XMLRPC libraries for many programming languages (including C, C++, Java, C#, Ruby, and Perl), and they can interoperate with each other. This is one the best methods to create applications that talk to each other independent of the programming language.
The XMLRPC client can also be implemented inside a web2py action, so that one action can talk to another web2py application (even within the same installation) using XMLRPC. Beware of session deadlocks in this case. If an action calls via XMLRPC a function in the same app, the caller must release the session lock before the call:
``
session.forget(response)
``:code
#### JSONRPC
-
``JSONRPC``:inxx
In this section we are going to use the same code example as for XMLRPC but we will expose the service using JSONRPC instead:
``
@service.jsonrpc
@service.jsonrpc2
def add(a,b):
return a+b
def call():
return service()
``:code
JSONRPC is very similar to XMLRPC but uses JSON instead of XML as data serialization protocol.
Of course we can call the service from any program in any language but here we will do it in Python. web2py ships with a module "gluon/contrib/simplejsonrpc.py" created by Mariano Reingart. Here is an example of how to use to call the above service:
``
>>> from gluon.contrib.simplejsonrpc import ServerProxy
>>> URL = "http://127.0.0.1:8000/app/default/call/jsonrpc"
>>> service = ServerProxy(URL, verbose=True)
>>> print service.add(1, 2)
``:code
-Use "http://127.0.0.1:8000/app/default/call/jsonrpc2" for jsonrpc2.

- A first part that identify the location of the service, i.e. the action that exposes the service:
``
http://127.0.0.1/myapp/default/api/
``
- The name of the resource (``person``, ``persons``, ``person/1``, etc.)
- The communication protocol specified by the extension.
Notice that we can always use the router to eliminate any unwanted prefix in the URL and for example simplify this:
``
http://127.0.0.1/myapp/default/api/person/1.json
``
into this:
``
http://127.0.0.1/api/person/1.json
``
yet this is a matter of taste and we have already discussed it at length in chapter 4.
In our example we used an action called ``api`` but this is not a requirement. We can in fact name the action that exposes the RESTful service any way we like and we can in fact even create more than one. For the sake of argument we will continue to assume that our RESTful action is called ``api``.
We will also assume we have defined the following two tables:
``
db.define_table('person',Field('name'),Field('info'))
db.define_table('pet',Field('owner',db.person),Field('name'),Field('info'))
``
and they are the resources we want to expose.
The first thing we do is create the RESTful action:
``
def api():
return locals()
``
Now we modify it so that the extension is filtered out of the request args (so that ``request.args`` can be used to identify the resource) and so that it can handle the different methods separately:
Notice that:
- GET perform a select and returns the record, ``db.person(id)``. The output is automatically converted to JSON because the generic view is called.
- POST performs a ``validate_and_insert(..)`` and returns the ``id`` of the new record or, alternatively, validation errors. The POST variables, ``**fields``, are the post variables.
#### ``parse_as_rest`` (experimental)
The logic explained so far is sufficient to create any type of RESTful web service yet web2py helps us even more.
In fact, web2py provides a syntax to describe which database tables we want to expose and how to map resource into URLs and vice versa.
``parse_as_rest``:inxx
This is done using URL patterns.
A pattern is a string that maps the request args from a URL into a database query.
There 4 types of atomic patterns:
- String constants for example "friend"
- String constant corresponding to a table. For example "friend[person]" will match "friends" in the URL to the "person" table.
- Variables to be used to filter. For example "{person.id}" will apply a ``db.person.name=={person.id}`` filter.
- Names of fields, represented by ":field"
Atomic patterns can be combined into complex URL patterns using "/" such as in
``
"/friend[person]/{person.id}/:field"
``
which gives a url of the form
``
http://..../friend/1/name
``
Into a query for a person.id that returns the name of the person. Here "friend[person]" matches "friend" and filters the table "person". "{person.id}" matches "1" and filters "person.id==1". ":field" matches "name" and returns:
``
db(db.person.id==1).select().first().name
``
Multiple URL patters can be combined into a list so that one single RESTful action can serve different types of requests.
The DAL has a method ``parse_as_rest(pattern,args,vars)`` that given a list of patterns, the ``request.args`` and the ``request.vars`` matches the pattern and returns a response (GET only).
def api():
"/friend/{person.name}/:field",
"/friend/{person.name}/pets[pet.owner]",
"/friend/{person.name}/pet[pet.owner]/{pet.name}",
"/friend/{person.name}/pet[pet.owner]/{pet.name}/:field"
]
parser = db.parse_as_rest(patterns,args,vars)
if parser.status == 200:
return dict(content=parser.response)
else:
raise HTTP(parser.status,parser.error)
def POST(table_name,**vars):
if table_name == 'person':
return db.person.validate_and_insert(**vars)
elif table_name == 'pet':
return db.pet.validate_and_insert(**vars)
else:
raise HTTP(400)
return locals()
``:code
Which understands the following URLs that correspond to the listed patterns:
- GET all persons
``
http://.../api/friends
``
- GET one person with name starting with "t"
``
http://.../api/friend/t
``
- GET the "info" field value of the first person with name equal to "Tim"
``
http://.../api/friend/Tim/info
``
- GET a list of pets of the person (friend) above
``
http://.../api/friend/Tim/pets
``
- GET the pet with name "Snoopy of person with name "Tim"
``
http://.../api/friend/Tim/pet/Snoopy
access granted, you said hello
### Services and Authentication
``Authentication``:inxx
In the previous chapter we have discussed the use of the following decorators:
``
@auth.requires_login()
@auth.requires_membership(...)
@auth.requires_permission(...)
``:code
For normal actions (not decorated as services), these decorators can be used even if the output is rendered in a format other than HTML.
For functions defined as services and decorated using the ``@service...`` decorators, the ``@auth...`` decorators should not be used. The two types of decorators cannot be mixed. If authentication is to be performed, it is the ``call`` actions that needs to be decorated:
``
@auth.requires_login()
def call(): return service()
``:code
Notice that it also possible to instantiate multiple service objects, register the same different functions with them, and expose some of them with authentication and some not:
``
+public_service=Service()
+private_service=Service()
- A first part that identify the location of the service, i.e. the action that exposes the service:
``
http://127.0.0.1/myapp/default/api/
``
- The name of the resource (``person``, ``persons``, ``person/1``, etc.)
- The communication protocol specified y the extension.
Notice that we can always use the router to eliminate any unwanted prefix in the URL and for example simplify this:
``
http://127.0.0.1/myapp/default/api/person/1.json
``
into this:
``
http://127.0.0.1/api/person/1.json
``
yet this is a matter of test and we have already discussed it at length in chapter 4.
In our example we used an action called ``api`` but this is not a requirement. We can in fact name the action that exposes the RESTful service any way we like and we can in fact even create more than one. For the sake of argument we will continue to assume that our RESTful action is called ``api``.
We will also assume we have defined the following two tables:
``
db.define_table('person',Field('name'),Field('info'))
db.define_table('pet',Field('owner',db.person),Field('name'),Field('info'))
``
and they are the resources we want to expose.
The first thing we do is create the RESTful action:
``
def api():
return locals()
``
Now we modify it so that the extension is filtered out of the request args (so that ``request.args`` can be used to identify the resource) and so that it can handle the different methods separately:
Notice that:
- GET perform a select and returns the record, ``db.person(id)``. The output is automatically converted to JSON because the generic view is called.
- POST performs a ``validate_and_insert(..)`` and returns the ``id`` of the new record or, alternatively, validation errors. The POST variables, ``**fields``, are the post variables.
#### ``parse_as_rest`` (experimental)
The logic explained so far is sufficient to create any type of RESTful web service yet web2py helps us even more.
In fact, web2py provides a syntax to describe which database tables we want to expose and how to map resource into URLs and vice versa.
``parse_as_rest``:inxx
This is done using URL patterns.
A pattern is a string that maps the request args from a URL into a database query.
There 4 types of atomic patterns:
- String constants for example "friend"
- String constant corresponding to a table. For example "friend[person]" will match "friends" in the URL to the "person" table.
- Variables to be used to filter. For example "{person.id}" will apply a ``db.person.name=={person.id}`` filter.
- Names of fields, represented by ":field"
Atomic patters can be combined into complex URL patters using "/" such as in
``
"/friend[person]/{person.id}/:field"
``
which gives a url of the form
``
http://..../friend/1/name
``
Into a query for a person.id that returns the name of the person. Here "friend[person]" matches "friend" and filters the table "person". "{person.id}" matches "1" and filters "person.id==1". ":field" matches "name" and returns:
``
db(db.person.id==1).select().first().name
``
Multiple URL patters can be combined into a list so that one single RESTful action can serve different types of requests.
The DAL has a method ``parse_as_rest(pattern,args,vars)`` that given a list of patterns, the ``request.args`` and the ``request.vars`` matches the pattern and returns a response (GET only).
def api():
"/friend/{person.name}/:field",
"/friend/{person.name}/pets[pet.owner]",
"/friend/{person.name}/pet[pet.owner]/{pet.name}",
"/friend/{person.name}/pet[pet.owner]/{pet.name}/:field"
]
parser = db.parse_as_rest(patterns,args,vars)
if parser.status == 200:
return dict(content=parser.response)
else:
raise HTTP(parser.status,parser.error)
def POST(table_name,**vars):
if table_name == 'person':
return db.person.validate_and_insert(**vars)
elif table_name == 'pet':
return db.pet.validate_and_insert(**vars)
else:
raise HTTP(400)
return locals()
``:code
Which understands the following URLs that correspond to the listed patters:
- GET all persons
``
http://.../api/friends
``
- GET one person with name starting with "t"
``
http://.../api/friend/t
``
- GET the "info" field value of the first person with name equal to "Tim"
``
http://.../api/friend/Tim/info
``
- GET a list of pets of the person (friend) above
``
http://.../api/friend/Tim/pets
``
- GET the pet with name "Snoopy of person with name "Tim"
``
http://.../api/friend/Tim/pet/Snoopy
access granted, you said hello
### Services and Authentication
``Authentication``:inxx
In the previous chapter we have discussed the use of the following decorators:
``
@auth.requires_login()
@auth.requires_membership(...)
@auth.requires_permission(...)
``:code
For normal actions (not decorated as services), these decorators can be used even if the output is rendered in a format other than HTML.
For functions defined as services and decorated using the ``@service...`` decorators, the ``@auth...`` decorators should not be used. The two types of decorators cannot be mixed. If authentication is to be performed, it is the ``call`` actions that needs to be decorated:
``
@auth.requires_login()
def call(): return service()
``:code
Notice that it also possible to instantiate multiple service objects, register the same different functions with them, and expose some of them with authentication and some not:
``
-public_services=Service()
-private_services=Service()

As an example of application here, we discuss the usage of JSON Remote Procedure Calls with Pyjamas. Pyjamas is a Python port of the Google Web Toolkit (originally written in Java). Pyjamas allows writing a client application in Python. Pyjamas translates this code into JavaScript. web2py serves the JavaScript and communicates with it via AJAX requests originating from the client and triggered by user actions.
Here we describe how to make Pyjamas work with web2py. It does not require any additional libraries other than web2py and Pyjamas.
We are going to build a simple "todo" application with a Pyjamas client (all JavaScript) that talks to the server exclusively via JSONRPC.
First, create a new application called "todo".
Second, in "models/db.py", enter the following code:
``
db=DAL('sqlite://storage.sqlite')
db.define_table('todo', Field('task'))
service = Service()
``:code
''(Note: Service class is from gluon.tools).''
Third, in "controllers/default.py", enter the following code:
``
def index():
redirect(URL('todoApp'))
You can obtain the WSDL for the service at
``
http://127.0.0.1:8000/app/default/call/soap?WSDL
``:code
And you can obtain documentation for any of the exposed methods:
``
http://127.0.0.1:8000/app/default/call/soap
``:code
### Low level API and other recipes
#### simplejson
``JSON``:inxx ``simplejson``:inxx
web2py includes gluon.contrib.simplejson, developed by Bob Ippolito. This module provides the most standard Python-JSON encoder-decoder.
SimpleJSON consists of two functions:
- ``gluon.contrib.simplesjson.dumps(a)`` encodes a Python object ``a`` into JSON.
- ``gluon.contrib.simplejson.loads(b)`` decodes the JSON data in ``b`` into a Python object.
JSONRPC is very similar to XMLRPC, but uses the JSON-based protocol instead of XML to encode the data. As an example of application here, we discuss its usage with Pyjamas. Pyjamas is a Python port of the Google Web Toolkit (originally written in Java). Pyjamas allows writing a client application in Python. Pyjamas translates this code into JavaScript. web2py serves the JavaScript and communicates with it via AJAX requests originating from the client and triggered by user actions.
Here we describe how to make Pyjamas work with web2py. It does not require any additional libraries other than web2py and Pyjamas.
We are going to build a simple "todo" application with a Pyjamas client (all JavaScript) that talks to the server exclusively via JSONRPC.
First, create a new application called "todo".
Second, in "models/db.py", enter the following code:
``
db=DAL('sqlite://storage.sqlite')
db.define_table('todo', Field('task'))
service = Service()
``:code
''(Note: Service class is from gluon.tools).''
Third, in "controllers/default.py", enter the following code:
``
def index():
redirect(URL('todoApp'))
You can obtain the WSDL for the service at
``
http://127.0.0.1:8000/app/default/call/soap?WSDL
``:code
And you can obtain documentation for any of the exposed methods:
``
http://127.0.0.1:8000/app/default/call/soap
``:code
### Low level API and other recipes
#### simplejson
``JSON``:inxx ``simplejson``:inxx
web2py includes gluon.contrib.simplejson, developed by Bob Ippolito. This module provides the most standard Python-JSON encoder-decoder.
SimpleJSON consists of two functions:
- ``gluon.contrib.simplesjson.dumps(a)`` encodes a Python object ``a`` into JSON.
- ``gluon.contrib.simplejson.loads(b)`` decodes a JavaScript object ``b`` into a Python object.

Third, you must decorate those functions you want to expose as a service. Here is a list of currently supported decorators:
``
@service.run
@service.xml
@service.json
@service.rss
@service.csv
@service.xmlrpc
@service.jsonrpc
+@service.jsonrpc2
@service.amfrpc3('domain')
@service.soap('FunctionName',returns={'result':type},args={'param1':type,})
``:code
As an example, consider the following decorated function:
``
@service.run
def concat(a,b):
return a+b
``:code
This function can be defined in a model or in the controller where the ``call`` action is defined. This function can now be called remotely in two ways:
``
http://127.0.0.1:8000/app/default/call/run/concat?a=hello&b=world
http://127.0.0.1:8000/app/default/call/run/concat/hello/world
``:code
In both cases the http request returns:
``
ZeroDivisionError: integer division or modulo by zero
The Python xmlrpclib module provides a client for the XMLRPC protocol. web2py acts as the server.
The client connects to the server via ServerProxy and can remotely call decorated functions in the server. The data (a,b) is passed to the function(s), not via GET/POST variables, but properly encoded in the request body using the XMLPRC protocol, and thus it carries with itself type information (int or string or other). The same is true for the return value(s). Moreover, any exception raised on the server propagates back to the client.
There are XMLRPC libraries for many programming languages (including C, C++, Java, C#, Ruby, and Perl), and they can interoperate with each other. This is one the best methods to create applications that talk to each other independent of the programming language.
The XMLRPC client can also be implemented inside a web2py action, so that one action can talk to another web2py application (even within the same installation) using XMLRPC. Beware of session deadlocks in this case. If an action calls via XMLRPC a function in the same app, the caller must release the session lock before the call:
``
session.forget(response)
``:code
#### JSONRPC
``JSONRPC``:inxx
In this section we are going to use the same code example as for XMLRPC but we will expose the service using JSONRPC instead:
``
@service.jsonrpc
+@service.jsonrpc2
def add(a,b):
return a+b
def call():
return service()
``:code
JSONRPC is very similar to XMLRPC but uses JSON instead of XML as data serialization protocol.
Of course we can call the service from any program in any language but here we will do it in Python. web2py ships with a module "gluon/contrib/simplejsonrpc.py" created by Mariano Reingart. Here is an example of how to use to call the above service:
``
>>> from gluon.contrib.simplejsonrpc import ServerProxy
>>> URL = "http://127.0.0.1:8000/app/default/call/jsonrpc"
>>> service = ServerProxy(URL, verbose=True)
>>> print service.add(1, 2)
``:code
+Use "http://127.0.0.1:8000/app/default/call/jsonrpc2" for jsonrpc2.
+
#### JSONRPC and Pyjamas
``JSONRPC``:inxx ``Pyjamas``:inxx
Third, you must decorate those functions you want to expose as a service. Here is a list of currently supported decorators:
``
@service.run
@service.xml
@service.json
@service.rss
@service.csv
@service.xmlrpc
@service.jsonrpc
@service.amfrpc3('domain')
@service.soap('FunctionName',returns={'result':type},args={'param1':type,})
``:code
As an example, consider the following decorated function:
``
@service.run
def concat(a,b):
return a+b
``:code
This function can be defined in a model or in the controller where the ``call`` action is defined. This function can now be called remotely in two ways:
``
http://127.0.0.1:8000/app/default/call/run/concat?a=hello&b=world
http://127.0.0.1:8000/app/default/call/run/concat/hello/world
``:code
In both cases the http request returns:
``
ZeroDivisionError: integer division or modulo by zero
The Python xmlrpclib module provides a client for the XMLRPC protocol. web2py acts as the server.
The client connects to the server via ServerProxy and can remotely call decorated functions in the server. The data (a,b) is passed to the function(s), not via GET/POST variables, but properly encoded in the request body using the XMLPRC protocol, and thus it carries with itself type information (int or string or other). The same is true for the return value(s). Moreover, any exception raised on the server propagates back to the client.
There are XMLRPC libraries for many programming languages (including C, C++, Java, C#, Ruby, and Perl), and they can interoperate with each other. This is one the best methods to create applications that talk to each other independent of the programming language.
The XMLRPC client can also be implemented inside a web2py action, so that one action can talk to another web2py application (even within the same installation) using XMLRPC. Beware of session deadlocks in this case. If an action calls via XMLRPC a function in the same app, the caller must release the session lock before the call:
``
session.forget(response)
``:code
#### JSONRPC
``JSONRPC``:inxx
In this section we are going to use the same code example as for XMLRPC but we will expose the service using JSONRPC instead:
``
@service.jsonrpc
def add(a,b):
return a+b
def call():
return service()
``:code
JSONRPC is very similar to XMLRPC but uses JSON instead of XML as data serialization protocol.
Of course we can call the service from any program in any language but here we will do it in Python. web2py ships with a module "gluon/contrib/simplejsonrpc.py" created by Mariano Reingart. Here is an example of how to use to call the above service:
``
>>> from gluon.contrib.simplejsonrpc import ServerProxy
>>> URL = "http://127.0.0.1:8000/app/default/call/jsonrpc"
>>> service = ServerProxy(URL, verbose=True)
>>> print service.add(1, 2)
``:code
#### JSONRPC and Pyjamas
``JSONRPC``:inxx ``Pyjamas``:inxx

``
@request.restful()
def api():
response.view = 'generic.json'
def GET(tablename,id):
if not tablename=='person': raise HTTP(400)
return dict(person = db.person(id))
def POST(tablename,**fields):
if not tablename=='person': raise HTTP(400)
return db.person.validate_and_insert(**fields)
return locals()
``
Notice that:
- the GET and POST are dealt with by different functions
- the function expect the correct arguments (un-named arguments parsed by ``request.args`` and named arguments are from ``request.vars``)
- they check the input is correct and eventually raise an exception
- GET perform a select and returns the record, ``db.person(id)``. The output is automatically converted to JSON because the generic view is called.
- POST performs a ``validate_and_insert(..)`` and returns the ``id`` of the new record or, alternatively, validation errors. The POST variables, ``**fields``, are the post variables.
#### ``parse_as_rest`` (experimental)
The logic explained so far is sufficient to create any type of RESTful web service yet web2py helps us even more.
In fact, web2py provides a syntax to describe which database tables we want to expose and how to map resource into URLs and vice versa.
``parse_as_rest``:inxx
patterns = [':auto[person]',':auto[pet]']
#### ``smart_query`` (experimental)
``smart_query``:inxx
There are times when you need more flexibility and you want to be able to pass to a RESTful service an arbitrary query like
``
http://.../api.json?search=person.name starts with 'T' and person.name contains 'm'
``
You can do this using
``
@request.restful()
def api():
response.view = 'generic.'+request.extension
def GET(search):
try:
rows = db.smart_query([db.person,db.pet],search).select()
return dict(result=rows)
except RuntimeError:
raise HTTP(400,"Invalid search string")
def POST(table_name,**vars):
return db[table_name].validate_and_insert(**vars)
return locals()
``
The method ``db.smart_query`` takes two arguments:
- a list of field or table that should be allowed in the query
- a string containing the query expressed in natural language
and it returns a ``db.set`` object with the records that have been found.
Notice that the search string is parsed, not evaluated or executed and therefore it provides no security risk.
#### Access Control
Access to the API can be restricted as usual by using decorators. So, for example
``
def call(): return service()
Notice that it also possible to instantiate multiple service objects, register the same different functions with them, and expose some of them with authentication and some not:
``
public_services=Service()
private_services=Service()
@public_service.jsonrpc
@private_service.jsonrpc
def f(): return 'public'
@private_service.jsonrpc
def g(): return 'private'
def public_call(): return public_service()
@auth.requires_login()
def private_call(): return private_service()
``:code
This assumes that the caller is passing credentials in the HTTP header (a valid session cookie or using basic authentication, as discussed in the previous section). The client must support it; not all clients do.
``
@request.restful()
def api():
response.view = 'generic.json'
def GET(tablename,id):
if not tablename=='person': raise HTTP(400)
return dict(person = db.person(id))
def POST(tablename,**fields):
if not tablename=='person': raise HTTP(400)
return db.person.validate_and_insert(**fields)
return locals()
``
Notice that:
- the GET and POST are dealt with by different functions
- the function expect the correct arguments (un-named arguments parsed by ``request.args`` and named arguments are from ``request.vars``)
- they check the input is correct and eventually raise an exception
- GET perform a select and returns the record, ``db.person(id)``. The output is automatically converted to JSON because the generic view is called.
- POST performs a ``validate_and_insert(..)`` and returns the ``id`` of the new record or, alternatively, validation errors. The POST variables, ``**fields``, are the post variables.
#### ``parse_as_rest`` (experimental)
The logic explained so far is sufficient to create any type of RESTful web service yet web2py helps us even more.
In fact, web2py provides a syntax to describe which database tables we want to expose and how to map resource into URLs and vice versa.
``parse_as_rest``:inxx
patterns = [':auto[person]',':auto[pet]']
#### ``smart_query`` (experimental)
``smart_query``:inxx
There are times when you need more flexibility and you want to be able to pass to a RESTful service an arbitrary query like
``
http://.../api.json?search=person.name starts with 'T' and person.name contains 'm'
``
You can do this using
``
@request.restful()
def api():
response.view = 'generic.'+request.extension
def GET(search):
try:
rows = db.smart_query([db.person,db.pet],search).select()
return dict(result=rows)
except RuntimeError:
raise HTTP(400,"Invalid search string")
def POST(table_name,**vars):
return db[table_name].validate_and_insert(**vars)
return locals()
``
The method ``db.smart_query`` takes two arguments:
- a list of field or table that should be allowed in the query
- a string containing the query expressed in natural language
and it returns a ``db.set`` object with the records that have been found.
Notice that the search string is parsed, not evaluated or executed and therefore it provides no security risk.
#### Access Control
Access to the API can be restricted as usual by using decorators. So, for example
``
def call(): return service()
Notice that it also possible to instantiate multiple service objects, register the same different functions with them, and expose some of them with authentication and some not:
``
public_services=Service()
private_services=Service()
@public_service.jsonrpc
@private_service.jsonrpc
def f(): return 'public'
@private_service.jsonrpc
def g(): return 'private'
def public_call(): return public_service()
@auth.requires_login()
def private_call(): return private_service()
``:code
This assumes that the caller is passing credentials in the HTTP header (a valid session cookie or using basic authentication, as discussed in the previous section). The client must support it; not all clients do.
-
-

``
>>> from gluon.contrib.simplejsonrpc import ServerProxy
>>> URL = "http://127.0.0.1:8000/app/default/call/jsonrpc"
>>> service = ServerProxy(URL, verbose=True)
>>> print service.add(1, 2)
``:code
#### JSONRPC and Pyjamas
``JSONRPC``:inxx ``Pyjamas``:inxx
JSONRPC is very similar to XMLRPC, but uses the JSON-based protocol instead of XML to encode the data. As an example of application here, we discuss its usage with Pyjamas. Pyjamas is a Python port of the Google Web Toolkit (originally written in Java). Pyjamas allows writing a client application in Python. Pyjamas translates this code into JavaScript. web2py serves the JavaScript and communicates with it via AJAX requests originating from the client and triggered by user actions.
Here we describe how to make Pyjamas work with web2py. It does not require any additional libraries other than web2py and Pyjamas.
We are going to build a simple "todo" application with a Pyjamas client (all JavaScript) that talks to the server exclusively via JSONRPC.
First, create a new application called "todo".
Second, in "models/db.py", enter the following code:
``
db=DAL('sqlite://storage.sqlite')
db.define_table('todo', Field('task'))
if __name__ == '__main__':
app = TodoApp()
app.onModuleLoad()
``:code
Sixth, run Pyjamas before serving the application:
``
cd /path/to/todo/static/
python /python/pyjamas-0.5p1/bin/pyjsbuild TodoApp.py
``:code
This will translate the Python code into JavaScript so that it can be executed in the browser.
To access this application, visit the URL:
``
http://127.0.0.1:8000/todo/default/todoApp
``:code
This subsection was created by Chris Prinos with help from Luke Kenneth Casson Leighton (creators of Pyjamas), updated by Alexei Vinidiktov. It has been tested with Pyjamas 0.5p1. The example was inspired by this Django page in ref.``blogspot1``:cite.
#### AMFRPC
``PyAMF``:inxx ``Adobe Flash``:inxx
``
>>> from gluon.contrib.simplejsonrpc import
>>> URL = "http://127.0.0.1:8000/app/default/call/jsonrpc"
>>> service = ServerProxy(URL, verbose=True)
>>> print service.add(1, 2)
``:code
#### JSONRPC and Pyjamas
``JSONRPC``:inxx ``Pyjamas``:inxx
JSONRPC is very similar to XMLRPC, but uses the JSON-based protocol instead of XML to encode the data. As an example of application here, we discuss its usage with Pyjamas. Pyjamas is a Python port of the Google Web Toolkit (originally written in Java). Pyjamas allows writing a client application in Python. Pyjamas translates this code into JavaScript. web2py serves the JavaScript and communicates with it via AJAX requests originating from the client and triggered by user actions.
Here we describe how to make Pyjamas work with web2py. It does not require any additional libraries other than web2py and Pyjamas.
We are going to build a simple "todo" application with a Pyjamas client (all JavaScript) that talks to the server exclusively via JSONRPC.
First, create a new application called "todo".
Second, in "models/db.py", enter the following code:
``
db=DAL('sqlite://storage.sqlite')
db.define_table('todo', Field('task'))
if __name__ == '__main__':
app = TodoApp()
app.onModuleLoad()
``:code
Sixth, run Pyjamas before serving the application:
``
cd /path/to/todo/static/
python /python/pyjamas-0.5p1/bin/pyjsbuild TodoApp.py
``:code
This will translate the Python code into JavaScript so that it can be executed in the browser.
To access this application, visit the URL:
``
http://127.0.0.1:8000/todo/default/todoApp
``:code
This subsection was created by Chris Prinos with help from Luke Kenneth Casson Leighton (creators of Pyjamas), updated by Alexei Vinidiktov. It has been tested with Pyjamas 0.5p1. The example was inspired by this Django page in ref.``blogspot1``:cite.
#### Amfrpc
``PyAMF``:inxx ``Adobe Flash``:inxx

Consider the following model:
``
db.define_table('animal',
Field('species'),
Field('genus'),
Field('family'))
``:code
Consider the following model:
``
db.define_model('animal',
Field('species'),
Field('genus'),
Field('family'))
``:code

## Services
``Web Services``:inxx ``API``:inxx
The W3C defines a web service as "a software system designed to support interoperable machine-to-machine interaction over a network". This is a broad definition, and it encompasses a large number of protocols designed not for machine-to-human communication, but for machine-to-machine communication such as XML, JSON, RSS, etc.
In this chapter we discuss how to expose web services using web2py. If you are interested in examples of consuming third party services (Twitter, Dropbox, etc.) you should look into Chapter 9 and Chapter 14.
web2py provides, out of the box, support for many protocols, including XML, JSON, RSS, CSV, XMLRPC, JSONRPC, AMFRPC, and SOAP. web2py can also be extended to support additional protocols.
Each of those protocols are supported in multiple ways, and we make a distinction between:
- Rendering the output of a function in a given format (for example XML, JSON, RSS, CSV)
- Remote Procedure Calls (for example XMLRPC, JSONRPC, AMFRPC)
### Rendering a dictionary
#### HTML, XML, and JSON
``HTML``:inxx ``XML``:inxx ``JSON``:inxx
Consider the following action:
``
def count():
session.counter = (session.counter or 0) + 1
return dict(counter=session.counter, now=request.now)
``:code
This action returns a counter that is increased by one when a visitor reloads the page, and the timestamp of the current page request.
Normally this page would be requested via:
``
and rendered in HTML. Without writing one line of code, we can ask web2py to ren
http://127.0.0.1:8000/app/default/count.html
http://127.0.0.1:8000/app/default/count.xml
http://127.0.0.1:8000/app/default/count.json
``:code
The dictionary returned by the action will be rendered in HTML, XML and JSON, respectively.
Here is the XML output:
``
<document>
<counter>3</counter>
<now>2009-08-01 13:00:00</now>
</document>
``:code
Here is the JSON output:
``
{ 'counter':3, 'now':'2009-08-01 13:00:00' }
``:code
Notice that date, time and datetime objects are rendered as strings in ISO format. This is not part of the JSON standard, but rather a web2py convention.
#### Generic views
When, for example, the ".xml" extension is called, web2py looks for a template file called "default/count.xml", and if it does not find it, looks for a template called "generic.xml". The files "generic.html", "generic.xml", "generic.json" are provided with the current scaffolding application. Other extensions can be easily defined by the user.
------
For security reasons the generic views are only allowed to be accessed on localhost. In order to enable the access from remote clients you may need to set the response.generic_patterns.
------
Assuming you are using a copy of scaffold app, edit the following line in models/db.py
- restrict access only to localhost
``
response.generic_patterns = ['*'] if request.is_local else []
``:code
- to allow all generic views
``
response.generic_patterns = ['*']
``:code
- to allow only .json
``
response.generic_patterns = ['*.json']
``:code
The generic_patterns is a glob pattern, it means you can use any patterns that matches with your app actions or pass a list of patterns.
``
animals.export_to_csv_file(stream)
response.headers['Content-Type']='application/vnd.ms-excel'
response.write(stream.getvalue(), escape=False)
}}
``:code
Notice that one could also define a "generic.csv" file, but one would have to specify the name of the object to be serialized ("animals" in the example). This is why we do not provide a "generic.csv" file.
### Remote procedure calls
``RPC``:inxx
web2py provides a mechanism to turn any function into a web service.
The mechanism described here differs from the mechanism described before because:
- The function may take arguments
- The function may be defined in a model or a module instead of controller
- You may want to specify in detail which RPC method should be supported
- It enforces a more strict URL naming convention
- It is smarter than the previous methods because it works for a fixed set of protocols. For the same reason it is not as easily extensible.
To use this feature:
First, you must import and initiate a service object.
``
from gluon.tools import Service
service = Service()
``:code
-------
This is already done in the "db.py" model file in the scaffolding application.
-------
Second, you must expose the service handler in the controller:
``
def call():
session.forget()
return service()
``:code
-------
This is already done in the "default.py" controller of the scaffolding application. Remove ``session.forget()`` if you plan to use session cookies with the services.
-------
def weekdays():
import gluon.contrib.simplejson
return gluon.contrib.simplejson.dumps(names)
``:code
Below is a sample HTML page that sends an Ajax request to the above action, receives the JSON message and stores the list in a corresponding JavaScript variable:
``
{{extend 'layout.html'}}
<script>
$.getJSON('/application/default/weekdays',
function(data){ alert(data); });
</script>
``:code
The code uses the jQuery function ``$.getJSON``, which performs the Ajax call and, on response, stores the weekdays names in a local JavaScript variable ``data`` and passes the variable to the callback function. In the example the callback function simply alerts the visitor that the data has been received.
#### PyRTF
``PyRTF``:inxx ``RTF``:inxx
Another common need of web sites is that of generating Word-readable text documents. The simplest way to do so is using the Rich Text Format (RTF) document format. This format was invented by Microsoft and it has since become a standard.
web2py includes gluon.contrib.pyrtf, developed by Simon Cusack and revised by Grant Edwards. This module allows you to generate RTF documents programmatically, including colored formatted text and pictures.
In the following example we initiate two basic RTF classes, Document and Section, append the latter to the former and insert some dummy text in the latter:
``
def makertf():
import gluon.contrib.pyrtf as q
doc=q.Document()
section=q.Section()
doc.Sections.append(section)
section.append('Section Title')
section.append('web2py is great. '*100)
response.headers['Content-Type']='text/rtf'
return q.dumps(doc)
``:code
In the end the Document is serialized by ``q.dumps(doc)``. Notice that before returning an RTF document it is necessary to specify the content-type in the header else the browser does not know how to handle the file.
Depending on the configuration, the browser may ask you whether to save this file or open it using a text editor.
#### ReportLab and PDF
``ReportLab``:inxx ``PDF``:inxx
web2py can also generate PDF documents, with an additional library called "ReportLab"``ReportLab``:cite .
In the case of web2py each request can be split into three parts:
``
http://127.0.0.1/myapp/default/api/
``
- The name of the resource (``person``, ``persons``, ``person/1``, etc.)
- The communication protocol specified y the extension.
Notice that we can always use the router to eliminate any unwanted prefix in the URL and for example simplify this:
``
http://127.0.0.1/myapp/default/api/person/1.json
``
into this:
``
http://127.0.0.1/api/person/1.json
``
yet this is a matter of test and we have already discussed it at length in chapter 4.
In our example we used an action called ``api`` but this is not a requirement. We can in fact name the action that exposes the RESTful service any way we like and we can in fact even create more than one. For the sake of argument we will continue to assume that our RESTful action is called ``api``.
We will also assume we have defined the following two tables:
``
db.define_table('person',Field('name'),Field('info'))
db.define_table('pet',Field('owner',db.person),Field('name'),Field('info'))
``
and they are the resources we want to expose.
The first thing we do is create the RESTful action:
``
def api():
return locals()
``
Now we modify it so that the extension is filtered out of the request args (so that ``request.args`` can be used to identify the resource) and so that it can handle the different methods separately:
``
which for out ``person`` and ``pet`` tables results in:
"/person/info/pet[pet.owner]/owner/{pet.owner}",
"/person/info/pet[pet.owner]/owner/{pet.owner}/:field",
"/pet[pet]",
"/pet/id/{pet.id}",
"/pet/id/{pet.id}/:field",
"/pet/owner/{pet.owner}",
"/pet/owner/{pet.owner}/:field"
]}
``
You can specify auto patterns for some tables only:
``
patterns = [':auto[person]',':auto[pet]']
``
#### ``smart_query`` (experimental)
``smart_query``:inxx
There are times when you need more flexibility and you want to be able to pass to a RESTful service an arbitrary query like
-
## Services
``Web Services``:inxx ``API``:inxx
The W3C defines a web service as "a software system designed to support interoperable machine-to-machine interaction over a network". This is a broad definition, and it encompasses a large number of protocols designed not for machine-to-human communication, but for machine-to-machine communication such as XML, JSON, RSS, etc.
In this chapter we discuss how to expose web services using web2py. If you are interested in examples of consuming third party services (Twitter, Dropbox, etc.) you should look into Chapter 9 and Chapter 14.
web2py provides, out of the box, support for many protocols, including XML, JSON, RSS, CSV, XMLRPC, JSONRPC, AMFRPC, and SOAP. web2py can also be extended to support additional protocols.
Each of those protocols is supported in multiple ways, and we make a distinction between:
- Rendering the output of a function in a given format (for example XML, JSON, RSS, CSV)
- Remote Procedure Calls (for example XMLRPC, JSONRPC, AMFRPC)
### Rendering a dictionary
#### HTML, XML, and JSON
``HTML``:inxx ``XML``:inxx ``JSON``:inxx
Consider the following action:
``
def count():
session.counter = (session.counter or 0) + 1
return dict(counter=session.counter, now=request.now)
``:code
This action returns a counter that is increased by one when a visitor reloads the page, and the timestamp of the current page request.
Normally this page would be requested via:
``
and rendered in HTML. Without writing one line of code, we can ask web2py to ren
http://127.0.0.1:8000/app/default/count.html
http://127.0.0.1:8000/app/default/count.xml
http://127.0.0.1:8000/app/default/count.json
``:code
The dictionary returned by the action will be rendered in HTML, XML and JSON, respectively.
Here is the XML output:
``
<document>
<counter>3</counter>
<now>2009-08-01 13:00:00</now>
</document>
``:code
Here is the JSON output:
``
{ 'counter':3, 'now':'2009-08-01 13:00:00' }
``:code
Notice that date, time, and datetime objects are rendered as strings in ISO format. This is not part of the JSON standard, but rather a web2py convention.
#### Generic views
When, for example, the ".xml" extension is called, web2py looks for a template file called "default/count.xml", and if it does not find it, looks for a template called "generic.xml". The files "generic.html", "generic.xml", "generic.json" are provided with the current scaffolding application. Other extensions can be easily defined by the user.
------
For security reasons the generic views are only allowed to be accessed on localhost. In order to enable the access from remote clients you may need to set the response.generic_patterns.
------
Assuming you are using a copy of scaffold app edit the following line in models/db.py
- restrict access only to localhost
``
response.generic_patterns = ['*'] if request.is_local else []
``:code
- to allow all generic views
``
response.generic_patterns = ['*']
``:code
- to allow only .json
``
response.generic_patterns = ['*.json']
``:code
The generic_patterns is a glob pattern, it means you can use any patterns that matches with your app actions or pass a list of patterns.
``
animals.export_to_csv_file(stream)
response.headers['Content-Type']='application/vnd.ms-excel'
response.write(stream.getvalue(), escape=False)
}}
``:code
Notice that one could also define a "generic.csv" file, but one would have to specify the name of the object to be serialized ("animals" in the example). This is why we do not provide a "generic.csv" file.
### Remote procedure calls
``RPC``:inxx
web2py provides a mechanism to turn any function into a web service.
The mechanism described here differs from the mechanism described before because:
- The function may take arguments
- The function may be defined in a model or a module instead of controller
- You may want to specify in detail which RPC method should be supported
- It enforces a more strict URL naming convention
- It is smarter than the previous methods because it works for a fixed set of protocols. For the same reason it is not as easily extensible.
To use this feature:
First, you must import and instantiate a service object.
``
from gluon.tools import Service
service = Service()
``:code
-------
This is already done in the "db.py" model file in the scaffolding application.
-------
Second, you must expose the service handler in the controller:
``
def call():
session.forget()
return service()
``:code
-------
This is already done in the "default.py" controller of the scaffolding application. Remove ``session.forget()`` if you plan to use session cookies with the services.
-------
def weekdays():
import gluon.contrib.simplejson
return gluon.contrib.simplejson.dumps(names)
``:code
Below is a sample HTML page that sends an Ajax request to the above action, receives the JSON message and stores the list in a corresponding JavaScript variable:
``
{{extend 'layout.html'}}
<script>
$.getJSON('/application/default/weekdays',
function(data){ alert(data); });
</script>
``:code
The code uses the jQuery function ``$.getJSON``, which performs the Ajax call and, on response, stores the weekdays names in a local JavaScript variable ``data`` and passes the variable to the callback function. In the example the callback function simply alerts the visitor that the data has been received.
#### PyRTF
``PyRTF``:inxx ``RTF``:inxx
Another common need of web sites is that of generating Word-readable text documents. The simplest way to do so is using the Rich Text Format (RTF) document format. This format was invented by Microsoft and it has since become a standard.
web2py includes gluon.contrib.pyrtf, developed by Simon Cusack and revised by Grant Edwards. This module allows you to generate RTF documents programmatically including colored formatted text and pictures.
In the following example we instantiate two basic RTF classes, Document and Section, append the latter to the former and insert some dummy text in the latter:
``
def makertf():
import gluon.contrib.pyrtf as q
doc=q.Document()
section=q.Section()
doc.Sections.append(section)
section.append('Section Title')
section.append('web2py is great. '*100)
response.headers['Content-Type']='text/rtf'
return q.dumps(doc)
``:code
In the end the Document is serialized by ``q.dumps(doc)``. Notice that before returning an RTF document it is necessary to specify the content-type in the header else the browser does not know how to handle the file.
Depending on the configuration, the browser may ask you whether to save this file or open it using a text editor.
#### ReportLab and PDF
``ReportLab``:inxx ``PDF``:inxx
web2py can also generate PDF documents, with an additional library called "ReportLab"``ReportLab``:cite .
In the case of web2py each request can be split into three parts:
``
http://127.0.0.1/myapp/default/api/
``
- The name of the resource (``person``, ``persons``, ``person/1``, etc.)
- The communication protocol specified y the extension.
Notice that we can always use the router to eliminate any unwanted prefix in the URL and for example simplify this:
``
http://127.0.0.1/myapp/default/api/person/1.json
``
into this:
``
http://127.0.0.1/api/person/1.json
``
yet this is a matter of test and we have already discussed it at length in chapter 4.
In our example we used an action called ``api`` but this is not a requirement. We can in fact name the action that exposes the RESTful service any way we like and we can in fact even create more than one. For the same of the argument we will continue to assume that our RESTful action is called ``api``.
We will also assume we have defined the following two tables:
``
db.define_table('person',Field('name'),Field('info'))
db.define_table('pet',Field('owner',db.person),Field('name'),Field('info'))
``
and they are the resources we want to expose.
The first thing we do is create the RESTful action:
``
def api():
return locals()
``
Now we modify it so that the extension is filtered out of the request args (so that ``request.args`` can be used to identify the resource) and so that it can handle the different methods separately:
``
which for out ``person`` and ``pet`` tables results in:
"/person/info/pet[pet.owner]/owner/{pet.owner}",
"/person/info/pet[pet.owner]/owner/{pet.owner}/:field",
"/pet[pet]",
"/pet/id/{pet.id}",
"/pet/id/{pet.id}/:field",
"/pet/owner/{pet.owner}",
"/pet/owner/{pet.owner}/:field"
]}
``
You can specify auto patterns for some tables only:
``
patterns = [':auto[person]',':auto[pet]']
``
#### ``smart_query`` (experimental)
``smart_query``:inxx
There are time when you need more flexibility and you want to be able to pass to a RESTful service an arbitrary query like