Serving XML-RPC from Rails 2.x
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.
Leave a Reply
You must be logged in to post a comment.