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