Lua XML-RPC Services

XML-RPC Home Page
XML-RPC Specification
XML-RPC @ Wikipedia

Creating a XML-RPC web service is virtually identical to how you create a JSON-RPC web service. The difference between the XML-RPC and the JSON-RPC is the name.

The following example illustrates the differences:

-- Load the JSON-RPC stack
local jsonrpc = require"jsonrpc"
-- Load the XML-RPC stack
local xmlrpc = require"xmlrpc"

-- Create the JSON-RPC service
local jsonService = jsonrpc.new("service name", serviceDescription)
-- Create the XML-RPC service
local xmlService  =  xmlrpc.new("service name", serviceDescription)

Just like the JSON-RPC stack parses the received JSON into Lua objects, the XML-RPC stack parses the received XML into identical Lua objects. The response is handled in a similar manner, the JSON-RPC stack automatically translates the response data to JSON and the XML-RPC stack automatically translates the response data to XML.

It is for this reason possible to use the same Lua service functions for serving as a XML-RPC service and as a JSON-RPC service. The following example extends the JSON-RPC directory service example to also serve as a XML-RPC service.

-- Load the JSON-RPC stack
local jsonrpc = require"jsonrpc"
-- Load the XML-RPC stack
local xmlrpc = require"xmlrpc"

-- The "add" JSON-RPC and XML-RPC service
local function add(a,b)
   return a + b
end

-- The "subtract" JSON-RPC and XML-RPC service
local function subtract(a,b)
   return a - b
end

-- The Service Description Object used by
-- the JSON-RPC and XML-RPC constructors
local serviceDescription = {
   math={
      add=subtract,
      subtract=subtract,
   }
}

-- Create the JSON-RPC service
local jsonService = jsonrpc.new("JSON-RPC service", serviceDescription)
-- Create the XML-RPC service
local xmlService = xmlrpc.new("XML-RPC service", serviceDescription)

-- The directory callback function.
-- Service JSON-RPC at relative path 'json-rpc' and
-- XML-RPC at relative path 'xml-rpc'
local function webservice(dir,func,path)
   if path == "json-rpc" then
      jsonService:execute(request, response)
   elseif path == "xml-rpc" then
      xmlService:execute(request, response)
   else -- No other services
      response:senderror(404)
   end
end

 -- Create directory: "web-service"
dir = ba.create.dir("web-service", webservice)
ba.dirtop():insert(dir) -- Insert into first root directory

In the above example, the math service is made available at the following URLs:
JSON-RPC clients: http://localhost/web-service/json-rpc
XML-RPC clients: http://localhost/web-service/xml-rpc

Binary Data and Time Conversion

Though JSON-RPC and XML-RPC provide similar capabilities, XML-RPC provides two types that cannot be represented in JSON. The two XML-RPC types dateTime.iso8601 and base64 requires special handling.

dateTime.iso8601

Time can be sent using ISO 8601 encoding. A limitation with the Barracuda XML-RPC stack is that time can only be represented as UNIX time, in other words time cannot be before January 1, 1970.

Receiving:

A dateTime.iso8601 encoded XML-RPC time is automatically converted to a number if the time is within the accepted UNIX time range. A date/time outside of the UNIX time range is returned as a string.

Sending:

You can explicitly tell the XML-RPC stack to return a UNIX time i.e. a number as dateTime.iso8601 encoding by calling xmlrpc.iso8601

The following service function illustrates how to return iso8601 encoded data/time:

local function currentTimeService()
   return xmlrpc.iso8601(os.time())
end

base64

B64 encoding is typically used when sending binary data. A string in Lua may contain any bytes and one can therefore store binary data in Lua strings.

Receiving:

When the XML-RPC stack receives B64 encoded data, the data is automatically converted to a Lua string.

Sending:

When the XML-RPC stack converts the response from a Lua XML-RPC service function to XML, strings are by default converted to the XML-RPC string type. The XML-RPC stack can send a Lua string as B64 encoded data, but you must explicitly tell the XML-RPC stack to do the conversion. The conversion is done by calling xmlrpc.base64

The following two service functions return response data as a XML-RPC string and as XML-RPC base64 encoded data respectively:

local function myService1()
   return "This is a string"
end

local function myService2()
   return xmlrpc.base64("This is a string encoded as B64")
end

Examples

The FuguHub CMS includes a Lua XML-RPC implementation for the metaweblog API. Many blog services support the metaweblog API. The API makes it possible for blog editors, such as Windows Live Writer, to upload blog entries and images to a metaweblog compliant blog engine.

You can download FuguHub, unzip cms.zip, and study the Lua XML-RPC metaweblog implementation in the metaweblog sub-directory.