Cocoa XML-RPC Demo

All of this code is really, really old! And not very good! You’re better off looking somewhere else!

XML-RPC is a Web Services protocol with implementations on lots of platforms and in lots of different languages.

It’s one way applications can call each other across the web.

Mac OS X 10.2 includes a new WebServicesCore framework which allows one to make XML-RPC calls from Cocoa apps. (And Carbon apps, too, by the way.)

This article will demonstrate making a very simple XML-RPC call and getting back the result. This article assumes you’re familiar with Cocoa: I won’t go through the steps involved to create outlets and actions and so on.

Note: I haven’t seen any documentation for the WebServicesCore framework yet. This article is based entirely on reading the header file and building an application that works. Please email any corrections or clarifications to me (brent at ranchero dot com).

Download

Download the source and project files for XMLRPCDemo.

App overview

Here’s what the demo app looks like:

You type in the number of a state, click the Get button, and then the corresponding state name is displayed.

The state name is retrieved by calling an XML-RPC server (betty.userland.com) that implements an XML-RPC method named examples.getStateName. It takes one paramater, the index of the state whose name you want.

Getting started

First I created the interface in Interface Builder, then hooked up the outlets and actions. (Open the project and take a look if you want.)

Then I wrote the fun part, the code that runs when you click the Get button. This is the code that makes the XML-RPC call and displays the result.

getStateName

In XMLRPCDemo.m see the getStateName method. (It’s the only method in that file.)

It starts by getting the state the user typed in. Then it creates an NSNumber object.

int ixState = [numberField intValue];
NSNumber *stateNum = [NSNumber numberWithInt: ixState];

Then it creates the variables we need to make the XML-RPC call. The WSMethodInvocationRef is a reference to the call itself. rpcURL is the URL of the XML-RPC server. methodName is the name of the XML-RPC we’ll call. params is a dictionary containing the parameters to send with the call. result is, of course, the result of the call.

WSMethodInvocationRef rpcCall;
NSURL *rpcURL = [NSURL URLWithString: @"http://betty.userland.com/RPC2"];
NSString *methodName = @"examples.getStateName";
NSDictionary *params = [NSDictionary dictionaryWithObject: stateNum forKey: @"foo"];
NSDictionary *result;

Creating the XML-RPC method invocation

Having set up our variables, we can create the XML-RPC method invocation.

rpcCall = WSMethodInvocationCreate ((CFURLRef) rpcURL, (CFStringRef) methodName, kWSXMLRPCProtocol);

The first parameter is the URL to the XML-RPC web service; the second parameter is the name of the XML-RPC method to call; the third parameter is a constant specifying the XML-RPC protocol. (See WSMethodInvocation.h, part of the CoreServices framework.)

Setting parameters

Then the parameters are set. Because we really want to see what happens when there’s an error, we do something tricky: we set the parameters only if the state number the user input is in the 1-50 range. Otherwise we set no parameters, which should cause an error to be returned from the XML-RPC server.

if ((ixState >= 1) && (ixState <= 50))
	WSMethodInvocationSetParameters (rpcCall, (CFDictionaryRef) params, NULL);

The first parameter is the XML-RPC method invocation created earlier; the second parameter is a dictionary containing the parameters; the third parameter is an optional array specifying the parameter order.

To re-iterate about the parameters: the parameters are stored in a dictionary as name/value pairs. If, for instance, one of the parameters should be a dictionary, then you have to put a dictionary inside the params dictionary.

Since there’s just one parameter, NULL is passed for parameter order.

Making the call

This is the easiest part. All the networking and everything is handled for you. Here’s the code:

result = (NSDictionary *) (WSMethodInvocationInvoke (rpcCall));

(Note how we’ve been using toll-free bridging between CoreFoundation types like CFDictionaries and Cocoa types like NSDictionaries. If you’re not familiar with CoreFoundation and toll-free bridging, I highly suggest learning about it.)

Displaying the result

If there was an error, we want to display the error string. If there was no error, we want to display the result string. Simply:

if (WSMethodResultIsFault ((CFDictionaryRef) result)) /*error?*/
	[resultField setStringValue: [result objectForKey: (NSString *) kWSFaultString]];
		
else /*no error; all's well*/
	[resultField setStringValue: [result objectForKey: (NSString *) kWSMethodInvocationResult]];		

One calls WSMethodResultIsFault with the result dictionary to find out if there was an error. If so, then the error string is in the result dictionary, with the key kWSFaultString.

If there was no error, the result is in the result dictionary with the key kWSMethodInvocationResult.

More

This is just about the simplest possible XML-RPC example. Reading the header file WSInvocation.h one notes that one can make asynchronous requests, call SOAP services, over-ride the built-in serializer, and more.

Lots to learn.

© 1995-2014 Ranchero Software, LLC