Multiplay Labs

tech hits and tips from Multiplay

Archive for the ‘Rails’ tag

Serving XML-RPC from Rails 2.x

with 3 comments

As part of our new Fileplay system, we’re implementing automated uploads of Match Demos at i35 direct to Fileplay. Our tournament admins at the events use ClanForge to manage the tournament, so we wanted to allow them to do it direct from there. Enter XML-RPC. ClanForge already speaks this, so it seemed the best way forward was to teach Rails to speak XML-RPC. Should be easy right?

Oh how wrong we were.

Googling around for a plugin to make this Just Work™ yielded results for Rails pre-2.0 using ActionWebService, which is now unused and “ousted”. Luckily, the solution is simple using XMLRPC4R

As XML-RPC generally only has one endpoint, we simply create a new controller with an index action which will do all the request handling.

Within the action, we start out by instantiating a basic class that knows how to speak XML-RPC.

xmlrpc = XMLRPC::BasicServer.new

The docs for XMLRPC4R say that we should never need to instantiate this. The key word here is “should”, normally it’s subclassed by something that does the handling of the HTTP stuff. Not in this case as Rails is handling that.

Now we want to hand off the request to the XML-RPC library.

response = xmlrpc.process(request.body.read)

If an exception gets raised within our handler, it’ll get automagically converted into an XML-RPC fault structure. But we still want the error to appear in our log:

# Log the error if there is one
parser = XMLRPC::XMLParser::XMLStreamParser.new
ret = parser.parseMethodResponse(response)
logger.error("XMLRPC fault raised. Code: #{ret[1].faultCode}: Message: #{ret[1].faultString}") unless ret[0]

Finally, render the XML-RPC response.

render :text => response, :layout => false

XML-RPC Methods

So how do we define methods that the consumers of our service can… consume?

Easy.

# Handler definitions
xmlrpc.add_handler("file.get") do |fileid|
	file = Multiplay::Fileplay::File.find_by_fileid(fileid)
	raise XMLRPC::FaultException.new 404, "File Not Found" if file.nil?
	file
end

Sure it’ll capture any raised Exceptions, but if you want to pass something meaningful to consumers, raise an XMLRPC::FaultException with a faultCode and a faultString.

Remember, as this is a block, you can’t return from it. The value to return over XML-RPC will be the value yielded, in this case the file.

Written by Boffbowsh

October 24th, 2008 at 9:14 am

Posted in Code

Tagged with ,