Flask-XML-RPC-Re¶
Flask-XML-RPC-Re 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 pip:
$ pip install Flask-XML-RPC-Re
A Simple Example¶
This is a REALLY simple example of how to create your own API using Flask-XML-RPC-Re.
from flask import Flask
from flask_xmlrpcre 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 flask_xmlrpcre.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 forregister_function()
, so you can use that too. You can also register an instance using theregister_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 theconnect()
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 hasregister()
andregister_function()
methods. These forward directly to theregister_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 asblog.new_post
.- Parameters:
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 flask_xmlrpcre.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 thenamespace()
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')
- Parameters:
prefix – The name to prefix the methods with.
- register(*args, **kwargs)¶
An alias for
register_function()
. As withXMLRPCHandler.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 flask_xmlrpcre.XMLRPCTester(client, rpc_path, allow_none=False)¶
This lets you conveniently make method calls using a Werkzeug
Client
, like the one returned byflask.Flask.test_client()
. You create it with theClient
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.
allow_none – Allow to pass None values.
- call(method, *params)¶
This calls the client’s
post
method with the responder path, the marshaled method call, and a content type oftext/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.
- flask_xmlrpcre.test_xmlrpc_call(client, rpc_path, method, *params, allow_none=False)¶
This makes a method call using a Werkzeug
Client
, such as the one returned byflask.Flask.test_client()
. It constructs the method call, makes the request, and then returns the response value or aFault
.- 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.
allow_none – Allow to pass None values.
- flask_xmlrpcre.dump_method_call(method, *params, allow_none=False)¶
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.
allow_none – Allow to marshal None values.
- flask_xmlrpcre.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.- Parameters:
response – The marshaled XML-RPC method response or fault.