Next Generation REST Web Services Client

I am currently working on a ton of Web Services related things for the Zend Framework, one of my favorite, is the almost complete, Zend_Rest_Client. This is a replacement for Zend_Rest (as we’re adding a server also).

Whilst it is almost impossible to emulate the PHP 5 SOAP extension, it is still possible to get a nice interface.

I could have made it so that if you call a method, other than the get/post/put/delete methods it would query a Zend REST server correctly, however I wanted to do something nice that was applicable to all REST web services. So I have come up with a client that allows the following three calls:

[php]
sayHello(‘Davey’, ‘Day’)->get();
?>
[/php]

This first one connects to a Zend_Rest_Server, and it therefore knows the format of the response and returns a string (in this case, it can also return arrays) directly from the get() call. The entire function will send the request:

http://..../service.php?method=sayHello&arg1=Davey&arg2=Day which the Zend_Rest_Server will translate to the TestClass::sayHello($who, $when); call (though it’s not a static call). TestClass is the class registered with the server – just like ext/soap.

Furthermore, there is a “fluent” API, for regular REST services:

[php]
method(‘flickr.test.echo’)->name(‘Davey Shafik’)->api_key($flickr_key)->get()->name;
?>
[/php]

This time, we need to access the name property on the return value for get(), this is because we don’t know the format of the response (it’s a call to the Flickr REST service), but you do. If there is only one node called name in the XML, we return it as a string (it’s overloaded), otherwise, you will get a SimpleXMLElement array (more on this after the next example); or null for nothing found.

This time, it calls http://api.flickr.com/services/rest/?method=flickr.test.echo&name=Davey%20Shafik&api_key={api key}.

The final look for a call, is just calling things normally, no fluentness:

[php]
key($key);
$technorati->url(‘http://pixelated-dreams.com’);

$result = $technorati->get();
echo $result->firstname .’ ‘. $result->lastname;
?>
[/php]

Here it calls http://api.technorati.com/bloginfo?key={key}&url=http%3A%2F%2Fpixelated-dreams.com

In this example, we call directly on $result->firstname and $result->lastname – these don’t exist in the root node of the XML returned, but to make things easier, if it is not found, an XPath for (in these cases) //firstname and //lastname is called respectively.

Again a string (shown here) or a SimpleXMLElement array is returned for multiple elements. These calls actually get the
document->result->weblog->author->firstname and document->result->weblog->author->lastname elements.

Whilst this could cause some problems (where same-named nodes are in different portions of the resulting XML and you want a specific one), you can still always access the elements as if the result was a SimpleXMLElement root node directly – this is simply a convenience that obviously pays off in this example.

The only outstanding item I have left is to recursively turn Zend_Rest_Server array responses into real arrays, this will stop you needed to (string) the nodes to use them. I think I will accomplish this using a wrapper object that implements ArrayAccess – this ensures the same result API those services that do use Zend_Rest_Server and those that don’t, whilst allowing OO access to the resulting values.

– Davey
P.S.
Eat My Shorts RoR