# RPC4Django Documentation

Version: 0.1.6

13 January 2010

Table of Contents

- Overview
  - Features
  - Project Website & More
    - Project Site
    - Demo Sites
    - Subversion Repository
  - Contributors
- License
- Installation
  - Prerequisites
  - Source Install Method
  - Easy Install Method
  - Pip Install Method
  - No Installation Method
- Configuration
  - Usual Setup
  - Remotely Calling Methods
    - XMLRPC
    - JSONRPC
- Additional Information and Settings
  - Running the Unit Tests
  - How RPC4Django Handles Requests
  - Method Summary
  - Optional Settings
  - Authentication
    - Setup
    - Usage
  - Access to the Request Object
- Planned Features
- Known Issues
- Changelog

## Overview

RPC4Django is an XMLRPC and JSONRPC server for Django powered projects. Simply plug it into any existing Django project and you can make your methods available via XMLRPC and JSONRPC. In addition, it can display nice documentation about the methods it makes available in a more customizable way than DocXMLRPCServer. RPC4Django is not affiliated with the Django Project.

### Features

- Detects request type (JSONRPC or XMLRPC) based on content
- Easy identification of RPC methods via a decorator
- Pure python and requires no external modules except Django
- Customizable RPC method documentation including reST
- Supports XMLRPC and JSONRPC introspection
- Supports method signatures (unlike SimpleXMLRPCServer)
- Easy installation and integration with existing Django projects
- Licensed for inclusion in open source and commercial software
- Ties in with Django's authentication and authorization

### Project Website & More

#### Project Site

- http://www.davidfischer.name/rpc4django

#### Demo Sites

- http://rpc4django.davidfischer.name
- https://rpcauth.davidfischer.name (user = pass = rpc4django, self signed certificate)

#### Subversion Repository

- https://svn.davidfischer.name/rpc4django/trunk (user = pass = rpc4django, self signed certificate)

### Contributors

- David Fischer (wish list)

## License

RPC4Django is licensed under the BSD license.

Copyright (c) 2009 - 2010, David Fischer

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
- Neither the name of rpc4django nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY David Fischer ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL David Fischer BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

## Installation

### Prerequisites

RPC4Django has been tested on Mac OS, Linux and Windows.

- Python 2.4 - 2.6
- Django 1.0+ (tested through 1.2.0 alpha)
- Docutils (optional)

### Source Install Method

This is the preferred method for installing RPC4Django.

    $> tar xvfz rpc4django-x.y.z.tar.gz
    $> cd rpc4django-x.y.z
    $> python setup.py install

### Easy Install Method

    $> easy_install rpc4django

### Pip Install Method

    $> pip install rpc4django

### No Installation Method

This method installs RPC4Django only for one specific django project but does not require any special system access.

    $> tar xvfz rpc4django-x.y.z.tar.gz
    $> cd rpc4django-x.y.z
    $> cp -r rpc4django YOUR_DJANGO_PROJECT_DIRECTORY

## Configuration

### Usual Setup

1. First, you need to add new url pattern to your root `urls.py` file. This file should be the one pointed to by `ROOT_URLCONF` in settings.py. You can replace `r'^RPC2$'` with anything you like.

   >     # urls.py
   >     #...
   >     urlpatterns = patterns('',
   >         # if installed via no install method
   >         #(r'^RPC2$', 'YOURPROJECT.rpc4django.views.serve_rpc_request'),

   >         # if installed via source or easy_install
   >         (r'^RPC2$', 'rpc4django.views.serve_rpc_request'),
   >     )

2. Second, add RPC4Django to the list of installed applications in your `settings.py`.

   >     # settings.py
   >     #...
   >     INSTALLED_APPS = (
   >         # if installed via no install
   >         #'YOURPROJECT.rpc4django',

   >         # if installed via source or easy_install
   >         'rpc4django',
   >     )

3. Lastly, you need to let RPC4Django know which methods to make available. This is done with the decorator `@rpcmethod`. RPC4Django imports all the apps in `INSTALLED_APPS` and makes any methods importable via `__init__.py` with the `@rpcmethod` decorator available as RPC methods. You can always write your RPC methods in another module and simply import it in `__init__.py`.

   >     # testapp/__init__.py
   >     from rpc4django import rpcmethod

   >     # This imports another method to be made available as an RPC method
   >     # This method should also have the @rpcmethod decorator
   >     # from mymodule import myrpcmethod

   >     # The doc string supports reST if docutils is installed
   >     @rpcmethod(name='mynamespace.add', signature=['int', 'int', 'int'])
   >     def add(a, b):
   >         '''Adds two numbers together
   >         >>> add(1, 2)
   >         3
   >         '''

   >         return a+b

   > The decorator `@rpcmethod` accepts three optional parameters:

   > - `name` - is the name under which the method will be made externally available. It defaults to the method's real name.
   > - `signature` - is the signature of the method and will be returned by calls to the XMLRPC introspection method `system.methodSignature`. It is of the form: `[return_value, arg1, arg2, arg3, ...]`. All of the types should be XMLRPC types (eg. struct, int, array, etc. -- see the XMLRPC spec for details). Since python is relatively loosely typed, all types are set to object by default.
   > - `permission` - the Django permission required to execute this method [new in 0.1.5]

### Remotely Calling Methods

#### XMLRPC

XMLRPC libraries exist in virtually every major programming language. The usage varies from library to library, but I'll give a python example using the xmlrpclib standard library:

    from xmlrpclib import ServerProxy
    s = ServerProxy('http://localhost:8000')
    s.system.listMethods()

#### JSONRPC

JSONRPC is less mature than XMLRPC and libraries are not as common. However, one of the main benefits of JSONRPC is that it can be used more easily from Javascript or Actionscript since JSON is their native format. There is an older JSONRPC library for python on json-rpc.org. Here is an example using that library:

    from jsonrpc import ServiceProxy
    s = ServiceProxy('http://localhost:8000')
    s.rpc4django.mytestmethod(1,2,3)

For an example of JSONRPC being used from Javascript running in a browser, please see the demo site.

## Additional Information and Settings

### Running the Unit Tests

The unit tests can be run using `manage.py`

    $> python manage.py test rpc4django

### How RPC4Django Handles Requests

- If the request is a GET request, return an HTML method summary
- A POST request with content-type header set to `text/xml` or `application/xml` will be processed as XMLRPC
- A POST request with content-type header containing `json` or `javascript` will be processed as JSONRPC
- Try to parse the POST data as xml. If it parses successfully, process it as XMLRPC
- Process it as JSONRPC

### Method Summary

- The method summary displays docstrings, signatures, and names from methods marked with the `@rpcmethod` decorator.
- The method summary allows testing of methods via JSONRPC (unless it is disabled)
- The summary is served (unless it is disabled) from a template `rpc4django/rpcmethod_summary.html` and can be customized in a similar way to the django admin.
- The method summary supports reST in docstrings if the docutils library is installed. Plain text is used otherwise. ReST warnings and errors are not reported in the output.

### Optional Settings

These are settings that can go in your project's `settings.py`:

`RPC4DJANGO_LOG_REQUESTS_RESPONSES=True|False` (default True)
  By default RPC4Django will log (using the python logging module) all requests and responses. This can be disabled by setting `RPC4DJANGO_LOG_REQUESTS_RESPONSES=False`.
`RPC4DJANGO_RESTRICT_INTROSPECTION=True|False` (default False)
  By default RPC4Django registers the standard XMLRPC and JSONRPC introspection functions. This can be disabled by setting `RPC4DJANGO_RESTRICT_INTROSPECTION=True`.
`RPC4DJANGO_RESTRICT_JSONRPC=True|False` (default False)
  If `RPC4DJANGO_RESTRICT_JSONRPC=True`, RPC4Django will never serve a JSONRPC request. Instead, either XMLRPC will be tried or status code 404 will be returned.
`RPC4DJANGO_RESTRICT_XMLRPC=True|False` (default False)
  If `RPC4DJANGO_RESTRICT_XMLRPC=True`, RPC4Django will never serve an XMLRPC request. Instead, either JSONRPC will be tried or status code 404 will be returned.
`RPC4DJANGO_RESTRICT_METHOD_SUMMARY=True|False` (default False)
  If `RPC4DJANGO_RESTRICT_METHOD_SUMMARY=True`, status code 404 will be returned instead of serving the method summary as a response to a GET request.
`RPC4DJANGO_RESTRICT_RPCTEST=True|False` (default False)
  If `RPC4DJANGO_RESTRICT_RPCTEST=True`, the method summary will not allow testing via JSONRPC.
`RPC4DJANGO_RESTRICT_REST=True|False` (default False) [new in 0.1.4]
  If `RPC4DJANGO_RESTRICT_REST=True`, RPC4Django does not attempt to convert any of the method summary docstrings to restructured text.
`RPC4DJANGO_HTTP_ACCESS_CREDENTIALS=True|False` (default False) [new in 0.1.6]
  RPC4Django will respond to OPTIONS requests with the HTTP header `Access-Control-Allow-Credentials` set to the given value. This pertains to allowing cross site requests with cookies. See the Mozilla documentation on requests with credentials for more details.
`RPC4DJANGO_HTTP_ACCESS_ALLOW_ORIGIN=URL|*` (default empty string) [new in 0.1.6]
  RPC4Django will respond to OPTIONS requests with the HTTP header `Access-Control-Allow-Origin` set to the given value. This pertains to allowing cross site requests. See the Mozilla documentation on preflighted requests for more details.

### Authentication

RPC4Django can be used with authenticated HTTP(s) requests and Django's authentication and authorization. [new in 0.1.5, requires Django 1.1+] It uses RemoteUserMiddleware or another derived middleware which is only built-in to Django 1.1 and higher. It is possible to use it with Django versions prior to 1.1, but it would require the `RemoteUserMiddleware` and the `RemoteUserBackend` to be added manually.

#### Setup

Firstly, the webserver should be configured to use basic HTTP authentication or some sort of single sign on (SSO) solution.

In settings.py, the following changes need to be made:

    MIDDLEWARE_CLASSES = (
        # ...
        # Must be enabled for RPC4Django authenticated method calls
        'django.contrib.auth.middleware.AuthenticationMiddleware',

        # Required for RPC4Django authenticated method calls
        # Requires Django 1.1+
        'django.contrib.auth.middleware.RemoteUserMiddleware',
    )

    # Required for RPC4Django authenticated method calls
    # Requires Django 1.1+
    AUTHENTICATION_BACKENDS = (
        'django.contrib.auth.backends.RemoteUserBackend',
    )

#### Usage

To protect a method, it needs to be defined with the `@rpcmethod` decorator and the `permission` parameter.

    from rpc4django import rpcmethod

    @rpcmethod(name='rpc4django.secret', signature=['string'], permission='auth.add_group')
    def secret():
        return "Successfully called a protected method"

To call an authenticated method from the Python command prompt, use the following:

    from xmlrpclib import ServerProxy
    s = ServerProxy('https://username:password@example.com')
    s.rpc4django.secret()

### Access to the Request Object

RPC4Django allows RPC methods to be written in such a way that they have access to Django's HttpRequest object. [new in 0.1.6] This can be used to see the type of request, the user making the request or any specific headers in the request object. To use this, methods must be written such that they can accept arbitrary keyword arguments. Although currently only the HttpRequest object is sent, additional keyword arguments may be sent in the future.

    @rpcmethod(name='rpc4django.httprequest',signature=['string'])
    def request(**kwargs):
        '''
        Illustrates access to the HttpRequest object
        '''

        return str(kwargs.get('request', None))

## Planned Features

- Add JSON class hinting
- Any requested features

## Known Issues

- There is a known issue that relates to but is not the same as Django Bug #6681. This bug sometimes raises an `AttributeError: Values instance has no attribute 'default_reference_context'` error when converting text to reST. The bug is very difficult to reproduce and the workaround specified in the Django bug is not relevant to RPC4Django since it does not change the default docutils role. A workaround is provided such that the exception is caught and the `rpc4django.templatetags.rpctags.resttext` function will return the plain text if `publish_parts` fails for any reason. This error is logged as fatal by RPC4Django's logger.

## Changelog

Version 0.1.6 (13 January 2010)

- Changed the XMLRPC dispatcher to allow sending nil which translates to the Python `None`. This was already allowed with JSONRPC
- Cross site request forgery (CSRF) framework support
- Added cross domain access control
- Added unit tests for base64 encoded binary
- Added access to HttpRequest object form inside a called RPC method

Version 0.1.5 (4 October 2009)

- Authenticated view that ties in with Django's auth system
- Added unicode unit test cases to verify that RPC4Django supports unicode (it does!)
- Added authenticated demo site (user = pass = rpc4django, self signed certificate)
- Improved the documentation stylesheet

Version 0.1.4 (31 August 2009)

- Provided a workaround for the bug relating to Django Bug #6681.
- Provided the settings.py option `RPC4DJANGO_RESTRICT_REST` which forces RPC4Django to not attempt to convert any of the method summary docstrings to restructured text.

Version 0.1.3 (15 July 2009)

- Fixed a serious bug where RPC4Django relied on `request.META['CONTENT_TYPE']` to be set by the web server
- Added generator tag to the template with RPC4Django and the version
- Renamed `RPC4DJANGO_RESTRICT_DOCUMENTATION` to `RPC4DJANGO_RESTRICT_METHOD_SUMMARY` for clarity
- Built out the example better so that it could be deployed as a demo without modification
- Improved JSON output formatting to be consistent with SimpleXMLRPCDispatcher's XML output

Version 0.1.2 (13 July 2009)

- Improved unit testing including adding support for testing views
- Fixed a minor bug involving the incorrect use of xmlrpclib.Fault which was causing some errors to be reported with the wrong error message
- Fetched the URL for the simple method descriptor using reverse()
- Enabled testing an RPC method directly from the method summary
- Fixed some failing unit tests on older python versions

Version 0.1.1 (11 July 2009)

- Improved documentation by integrating reST
- Allowed reST markup in rpcmethod docstrings
- Fix easy_install problems related to django templates
- Tested version compatibility
- Allowed analyzing post data when content-type cannot tell whether the data is XML or JSON

Version 0.1.0 (6 July 2009)

- First version of RPC4Django