XML-RPC is a very simple standard XML-based protocol for calling web services. XML-RPC is a much smaller protocol than the other leading XML-based web service protocol, SOAP. The complete specifications for XML-RPC in HTML is less than 20K bytes. The specifications for SOAP 1.2 in HTML is 8 times as large. As a result, there are many implementations of XML-RPC in many different languages, including Perl, Python, C++, Java, Lisp, etc. A number of examples of using XML-RPC in various languages is given at the XML-RPC How To site.

XML-RPC is very stable. XML-RPC's inventor, Dave Winer, has resisted changes, even quite modest and reasonable ones, because they would break existing XML-RPC servers and clients.

A personal history by Winer of how XML-RPC and SOAP relate is here.

In Lisp, an easy way to get started with XML-RPC is to use the The S-XML-RPC library. This document describes how to set up the library, and call and define XML-RPC services.

Install S-XML-RPC

Allegro: Install S-XML-RPC by downloading s-xml-rpc.zip and extracting the files into your CS325 code directory. Allegro has a very similar NET.XML-RPC package, but it uses a very different approach to defining XML-RPC services.

LispWorks: You need do nothing for this step.

Load S-XML-RPC

You will need to load S-XML-RPC whenever you restart Lisp. To do this simply, download load-s-xml-rpc.lisp to your CS325 directory and load it. It will do the appropriate thing for Allegro or LispWorks.

If you want to do this automatically, put a command to load the file in your cs325.lisp file.

Test calling XML-RPC functions

Start Lisp, load your 325 startup file, and load S-XML-RPC.

Try both of these XML-RPC method calls:

(xml-rpc-call
   (encode-xml-rpc-call "examples.getStateName" 41)
   :host "betty.userland.com")

(xml-rpc-call
  (encode-xml-rpc-call "math.SumAndDifference" 5 2)
  :host "www.cookcomputing.com"
  :url "/xmlrpcsamples/math.rem")

The function encode-xml-rpc-call constructs a string with the XML to send to the server, e.g.,

 > (encode-xml-rpc-call "examples.getStateName" 41)
"<methodCall><methodName>examples.getStateName</methodName>
<params><param><value><int>41</int></value></param>
</params></methodCall>"

xml-rpc-call then sends this XML to the server specifed. The server consists of a host, a port, and a path, specified by the keywords host, :port and :url.These default to localhost, 80, and /RPC2, respectively.

Starting an XML-RPC server

When you know you can call XML-RPC functions, it's time to set up your own server. If you have two machines with Lisp that can see each other on the network, try putting the server example on a different machine. You will need to know the network name or IP address of the server machine to call it from the client machine.

On the server machine, download xml-rpc-server-example.lisp to your CS325 directory. Open the file in your Lisp editor. It shows how to define functions that can be called as web services remotely via XML-RPC. For example, to define lisp.GCD to be an XML-RPC callable greatest common divisor function:

(defun s-xml-rpc-exports::|lisp.GCD| (m n)
  (gcd m n))

S-XML-RPC will take care of converting the input parameters from the strings that were sent over the network into numbers, and converting the returned value back into a string to send back to the client.

The parameters for XML-RPC methods should be kept simple, i.e., numbers, strings, and simple lists and structures, because of that's what the XML-RPC protocol allows. Similarly, the function should return either a number, string, simple list, or structure.

"Structure" here means an XML-RPC structure, which is a list of name-value pairs. In S-XML-RPC client code in Lisp, you create an XML-RPC structure with (s-xml-rpc:xml-rpc-struct key value key value ...). In XML-RPC server code in Lisp, you get at parts of an XML-RPC structure with (s-xml-rpc:get-xml-rpc-struct-member struct key).

Load xml-rpc-server-example.lisp. Start the server with

(setq *xml-server* (s-xml-rpc:start-xml-rpc-server))

If you're running a web server on your machine on the default port 80, specify a different port for your XML-RPC server, e.g.,

(setq *xml-server* (s-xml-rpc:start-xml-rpc-server :port 8080))

You'll need to include :port 8080 when calling your server. When you're done testing, be sure to stop the server with:

(s-xml-rpc:stop-server *xml-server*)

It's a security risk to leave a public service running on your computer.

Call your server from Lisp

On your client machine (which might be your server machine), download xml-rpc-client-example.lisp and open it in your editor. This has code to call the functions that your server is providing. For example, the following function calls lisp.GCD:

(defun call-for-gcd (m n)
  (xml-rpc-call
   (encode-xml-rpc-call "lisp.GCD" m n)))

Load this code into Lisp, and use WITH-XML-SERVER to specify the server:

(with-xml-server (:host "myserver.org")
  (call-for-gcd 36 63))

If your server doesn't have a name, find out the IP address of the host and use that, e.g.,

(with-xml-server (:host "70.84.113.44")
  (call-for-gcd 36 63))

What is XML-RPC good for?

An appropriate XML-RPC service is one that:

For example, a web service that retrieve book information given an ISBN number would make sense, but one that retrieved the contents of the book, would be inappropriate as well as illegal. Also inappropriate would be a web service to calculate square roots, because this is so easily done on the client machine.


Testing your server from other languages

Of course, using Lisp to call Lisp doesn't prove much. More interesting is to call your XML-RPC method from a totally different client, in another language, perhaps on a different machine. Two examples are given below.

Testing your server with Python

If you have Python installed, then it's easy to test XML-RPC because Python comes with an XML-RPC library. Just start your Python interpreter, import the library xmlrpclib, and call the function xmlrpclib.ServerProxy to create an object that can be then used to call your XML-RPC methods. How it works may be a bit confusing, but the calling pattern is quite simple. For example, to call our GCD function above:

# get the library
import xmlrpclib

# get the server proxy and use it to call lisp.GCD()
xmlrpclib.ServerProxy("http://localhost:8080/RPC2").lisp.GCD(12155, 130130)

More about Python and XML-RPC can be found here.


Testing your server with Java

The easiest way test to XML-RPC with Java is to use xml-rpc-test.jar, a Java Archive I created by merging version 1.3 of the Apache Commons Codec library, and version 2 of the Apache XML-RPC library. (Note: version 3 of this library does not provide a utility class for calling XML-RPC directly.)

To install, download xml-rpc-test.jar to some directory, e.g., c:\java\xml-rpc\.

To test an XML-RPC method:

For example, to test the state name service,

C:\java\xml-rpc>java -jar xml-rpc-test.jar http://betty.userland.com/RPC2 examples.getStateName 32
    New York

To test the GCD service above:

C:\java\xml-rpc>java -jar xml-rpc-test.jar http://localhost:8080/RPC2 lisp.GCD 12155 130130
    715

When you're done, for safety, be sure to stop the XML-RPC server in Lisp, with

(stop-server *xml-server*)
Faculty: Chris Riesbeck
Time: MWF: 11:00am-11:50am
Location: Tech LR 5

Contents

Important Links