Flask-XML-RPC

Flask-XML-RPC is an extension for Flask that makes it easy to create APIs based on the XML-RPC standard.

Features

  • Easy registration of methods and namespacing
  • Connects seamlessly to your Flask app
  • Includes plenty of testing helpers

Install

If you’re using easy_install, then run this command to install Flask-XML-RPC:

$ easy_install Flask-XML-RPC

Or, if you’re using pip (which is recommended, since it’s awesome):

$ pip install Flask-XML-RPC

A Simple Example

This is a REALLY simple example of how to create your own API using Flask-XML-RPC.

from flask import Flask
from flaskext.xmlrpc import XMLRPCHandler, Fault

app = Flask(__name__)

handler = XMLRPCHandler('api')
handler.connect(app, '/api')

@handler.register
def hello(name="world"):
    if not name:
        raise Fault("unknown_recipient", "I need someone to greet!")
    return "Hello, %s!" % name

app.run()

Namespacing

Of course, the register_function() method can take a name if you want to use dotted names, but it’s easier to use namespaces. You get a namespace by calling the namespace() method with the prefix you want (without the dot).

handler = XMLRPCHandler('api')
blog = handler.namespace('blog')

@blog.register
def add_post(title, text):
    # do whatever...
    pass

The add_post function will then be available as blog.add_post. You can create namespaces from namespaces, as well.

blog_media = blog.namespace('media')

@blog_media.register
def delete(filename):
    # do whatever...
    pass

In this case, delete will be available as blog.media.delete. Namespacing can help you organize your API in a logical way.

Testing Your API

The easiest way to test your application is with the XMLRPCTester. It takes a werkzeug.TestClient and the path to your responder. When called with the method and params, it will marshal it, make a fake POST request to the responder with the client, and demarshal the result for you, returning it or a Fault.

If you’re using a unittest-based setup like the one described in the Flask documentation, you could use the XMLRPCTester like:

def test_hello(self):
    tester = XMLRPCTester(self.app, '/api')
    assert tester('hello') == 'Hello, world!'
    assert tester('hello', 'Steve') == 'Hello, Steve!'
    fault = tester('hello', '')
    assert fault.faultCode == 'unknown_recipient'

XMLRPCTester is actually a wrapper for test_xmlrpc_call(), which takes the client, responder path, method, and params.

If you prefer to marshal the XML-RPC data and make the requests yourself, the two functions dump_method_call() and load_method_response() are useful wrappers around the low-level xmlrpclib marshaling functions.

Using Your API

Practically all programming languages can use XML-RPC. In Python, you can call XML-RPC methods with the standard library xmlrpclib module.

>>> import xmlrpclib
>>> server = xmlrpclib.ServerProxy('http://localhost:5000/')
>>> server.hello()
'Hello, world!'
>>> server.hello('Steve')
'Hello, Steve!'

For other languages, please check their documentation.

API Documentation

class flaskext.xmlrpc.XMLRPCHandler(endpoint_name=None, instance=None, introspection=True, multicall=False)

This is the basic XML-RPC handler class. To use it, you create it:

handler = XMLRPCHandler('api')

Then, you can register functions with the register() method:

@handler.register
def spam():
    pass

register() is just an alias for register_function(), so you can use that too. You can also register an instance using the register_instance() method, and any methods on said instance will be exposed if they do not start with an _.

Then, you connect it to a Flask instance or a Flask module with the connect() method, like this:

handler.connect(app, '/')
Parameters:
  • endpoint_name – The name to use as an endpoint when connected to an app or module. If not specified here, you specify when you call connect().
  • instance – The instance to register and expose the methods of.
  • introspection – Whether to register the introspection functions, like system.listMethods. (It will by default.)
  • multicall – Whether to register the system.multicall function. (It won’t by default.)
connect(app_module, route, endpoint_name=None)

Connects the handler to an app or module. You have to provide the app and the URL route to use. The route can’t contain any variable parts, because there is no way to get them to the method.

handler.connect(app, '/api')
Parameters:
  • app_module – The app or module to connect the handler to.
  • route – The URL route to use for the handler.
  • endpoint_name – The name to use when connecting the endpoint.
handle_request()
This is the actual request handler that is routed by connect(). It takes the request data, dispatches the method, and sends it back to the client.
namespace(prefix)

This returns a XMLRPCNamespace object, which has register() and register_function() methods. These forward directly to the register_function() method of the parent they were created from, but they will prepend the given prefix, plus a dot, to the name registered. For example:

blog = handler.namespace('blog')

@blog.register
def new_post(whatever):
    pass

would make new_post available as blog.new_post.

Parameter:prefix – The name to prefix the methods with.
register(*args, **kwargs)
An alias for register_function().
register_function(function, name=None)

This will register the given function. There are two ways to use it.

As a plain old method, with or without a name:

handler.register_function(spam)
handler.register_function(spam, 'spam')

As a decorator, also with or without a name:

@handler.register_function
def spam():
    pass

@handler.register_function('spam')
def spam():
    pass

It’s shorter and easier to use register(), however, as it does the exact same thing.

Parameters:
  • function – The function to register. (In the named decorator form, this is the function’s name.)
  • name – The name to use, except in the named decorator form. If not given, the function’s __name__ attribute will be used.
register_instance(instance, allow_dotted_names=False)

This registers any kind of object. If the requested method hasn’t been registered by register_function(), it will be checked against the instance. You can only have one instance at a time, however.

If allow_dotted_names is True, the name will be split on the dots and the object will be traveled down recursively. However, this is a HUGE SECURITY LOOPHOLE, as while private methods (starting with _) will not be exposed, it’s still possible that someone could get access to your globals and do very bad things. So don’t do it unless you have a very good reason.

Parameters:
  • instance – The instance to register.
  • allow_dotted_names – Whether to resolve dots in method names. You probably shouldn’t.
class flaskext.xmlrpc.XMLRPCNamespace(handler, prefix)

This is a simple proxy that can register methods, and passes them on to the XMLRPCHandler that created it with a given name added as a prefix (with a dot). For more nesting, you can create namespaces from namespaces with the namespace() method.

Parameters:
  • handler – The handler to pass the methods to.
  • prefix – The prefix to give to the assigned methods. A dot will be appended.
namespace(name)

Returns another namespace for the same handler, with the given name postfixed to the current namespace’s prefix. For example,

handler.namespace('foo').namespace('bar')

gives the same result as:

handler.namespace('foo.bar')
Parameter:prefix – The name to prefix the methods with.
register(*args, **kwargs)
An alias for register_function(). As with XMLRPCHandler.register(), it’s shorter and easier to type.
register_function(function, name=None)

Registers a function. Use is the same as with the XMLRPCHandler.register_function() method.

Parameters:
  • function – The function to register. (In the named decorator form, this is the function’s name.)
  • name – The name to use, except in the named decorator form. If not given, the function’s __name__ attribute will be used.

Testing API

class flaskext.xmlrpc.XMLRPCTester(client, rpc_path)

This lets you conveniently make method calls using a Werkzeug Client, like the one returned by flask.Flask.test_client(). You create it with the Client and the path to the responder, and then you call it with the method and params.

Parameters:
  • client – A werkzeug.Client.
  • rpc_path – The path to the XML-RPC handler.
call(method, *params)

This calls the client’s post method with the responder path, the marshaled method call, and a content type of text/xml. It will return the unmarshaled response or fault.

You can just call the instance like a function for the same effect. These two calls are equivalent:

tester.call('hello', 'world')
tester('hello', 'world')
Parameters:
  • method – The name of the method to call.
  • params – The parameters to pass to the method.
flaskext.xmlrpc.test_xmlrpc_call(client, rpc_path, method, *params)

This makes a method call using a Werkzeug Client, such as the one returned by flask.Flask.test_client(). It constructs the method call, makes the request, and then returns the response value or a Fault.

Parameters:
  • client – A werkzeug.Client.
  • rpc_path – The path to the XML-RPC handler.
  • method – The method to call.
  • params – The parameters to pass to the method.
flaskext.xmlrpc.dump_method_call(method, *params)

This marshals the given method and parameters into a proper XML-RPC method call. It’s very useful for testing.

Parameters:
  • method – The name of the method to call.
  • params – The parameters to pass to the method.
flaskext.xmlrpc.load_method_response(response)

This returns the actual value returned from an XML-RPC response. If it’s a Fault instance, it will return the fault instead of the value. This is also useful for testing.

Parameter:response – The marshaled XML-RPC method response or fault.