Tag Archives: webservice
Accessing the Magento Web API
Fatal error: Uncaught SoapFault exception: [2] Access denied.
Further investigation led me to this forum post – web services are separate users and you must first set them up through the admin screens – and make sure also to allocate roles to them.
The slight pitfall at this point is that you create a username and an API key – these then become the apiUser and apiKey variables mentioned in the documentation. The key is basically a password, its starred out in the settings and you have to enter it twice. Now I know that, I can log in to my service! Hope this helps someone else get to the point faster than I did.
GETting RESTful collections – may I filter?
RESTful collections
So, when you are retrieving information from a RESTful service. You have two options: retrieve a specific resource, whose URL you know; or retrieve a collection, which may contain a list of resources. I’ve also seen some nice ways of filtering collections, by creating kind of “sub collections” or “views”, similar to what twitter does with the URL of lists, for example http://twitter.com/dpcon/speakers10 which is like a filtered list of twitter users.
What if I want to search and sort?
Is it RESTful to add GET parameters to a collection in order to add functionality such as filtering, sorting, or pagination? What I have in mind is a URL that looks something like this:
- http://example.com/users?orderby=firstname&start=0
- http://example.com/users?start=0&limit=25
- http://example.com/users?active=1&orderby=join_date&limit=12
This is what I would do with a search results page in a web application, and I use the same approach to web services which works really well and I recommend it to everyone! But is it RESTful?
I am also wondering where OpenSearch would fit into the answer for all this, I only noticed it recently but the more I look at it the more I think it could be an interesting addition!
Thoughts, links for me to RTFM, and all other additions are welcome in the comments box :)
Supermondays: Recap
My talk was entitled “PHP and Web Services: Perfect Partners” – the slides are on slideshare if you want to take a look. There was also a talk about android development by Alex Reid, including a live coding demo which went surprisingly well! Judging by the various events that were plugged and discussed on the night, at the main event and in the pub afterwards, this is a diverse and vibrant technical community – so if you are in the northeast, get along to Supermondays!
PHP and JSON
Writing JSON From PHP
Imagine we have a multidimensional array in PHP that looks something like this:
$menu['starter'] = array( "prawn cocktail",
"soup of the day");
$menu['main course'] = array( "roast chicken",
"fish 'n' chips",
"macaroni cheese");
$menu['pudding'] = array( "cheesecake",
"treacle sponge");
echo json_encode($menu);
The output of this script looks like this:
{"starter":["prawn cocktail","soup of the day"],"main course":["roast chicken","fish 'n' chips","macaroni cheese"],"pudding":["cheesecake","treacle sponge"]}
This is pretty typical of a JSON output string – you can see the curly brackets to enclose the whole thing, then some square brackets to show the nesting levels within the key/value formats. JSON is an ideal format for many applications because it is easy to understand and debug, its quite concise, and many languages have built-in support just like PHP.
Reading JSON Data From PHP
Once we’ve serialised the string, we might want to unserialise it again – and the PHP code for that is every bit as simple as the previous example, except that we use the function json_decode() instead of json_encode(). I’ve set the output of the previous script as the input to this one:
$json = '{"starter":["prawn cocktail","soup of the day"],"main course":["roast chicken","fish \'n\' chips","macaroni cheese"],"pudding":["cheesecake","treacle sponge"]}';
print_r(json_decode($json));
This decodes the string and then dumps it using print_r() – the output of my script looked like this:
stdClass Object
(
[starter] => Array
(
[0] => prawn cocktail
[1] => soup of the day
)
[main course] => Array
(
[0] => roast chicken
[1] => fish 'n' chips
[2] => macaroni cheese
)
[pudding] => Array
(
[0] => cheesecake
[1] => treacle sponge
)
)
Note that the data isn’t identical to how it looked when it went in – JSON can’t distinguish between arrays and objects, and doesn’t retain information about data types. So its perfect for a web service where we just want to convey the information, but may be too loose for other applications.
The examples here were taken from a talk I give about consuming web services – you can see all the slides on slideshare. If you have any additions or alternatives, leave a comment!
Speaking at PHPNW February
Three Ways to Make a POST Request from PHP
I’ve been doing a lot of work with services and working with them in various ways from PHP. There are a few different ways to do this, PHP has a curl extension which is useful, and if you can add PECL extensions then pecl_http is a better bet but there are a couple of different ways of using it. This post shows all these side-by-side.
POSTing from PHP Curl
This is pretty straightforward once you get your head around the way the PHP curl extension works, combining various flags with setopt() calls. In this example I’ve got a variable $xml which holds the XML I have prepared to send – I’m going to post the contents of that to flickr’s test method.
$url = 'http://api.flickr.com/services/xmlrpc/';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
First we initialised the connection, then we set some options using setopt(). These tell PHP that we are making a post request, and that we are sending some data with it, supplying the data. The CURLOPT_RETURNTRANSFER flag tells curl to give us the output as the return value of curl_exec rather than outputting it. Then we make the call and close the connection – the result is in $response.
POSTing from Pecl_Http
Pecl_Http has two interfaces – one procedural and one object-oriented; we’ll start by looking at the former. This is even simpler than in curl, here’s the same script translated for pecl_http:
$url = 'http://api.flickr.com/services/xmlrpc/';
$response = http_post_data($url, $xml);
This extension has a method to expressly post a request, and it can optionally accept data to go with it, very simple and easy.
POSTing from Pecl_Http: the OO interface
Finally let’s see what the OO verison of the extension looks like. Exactly the same call as both the above examples, but using the alternative interface, means our code looks like this:
$url = 'http://api.flickr.com/services/xmlrpc/';
$request = new HTTPRequest($url, HTTP_METH_POST);
$request->setRawPostData($xml);
$request->send();
$response = $request->getResponseBody();
This example is quite a bit longer than the previous one, and you might think this indicates that this approach is more complicated. In some senses that is true and its probably overkill for our extremely trivial example. However it is worth mentioning that the pecl_http extension is extremely flexible and powerful, and can handle some cases that the curl extension can’t. So even if it looks more complicated here, it can still be an excellent choice to implement.
In Conclusion
That was a very fast round-up of three ways you could make an arbitrary web service call from PHP – hopefully these examples are clear and will help anyone just starting to implement something along these lines.
Add a heartbeat method to your service
I’ve worked with a couple of services recently that have a rather excellent feature – a method which calls the service but doesn’t do anything useful but simply lets you know the service is alive and well and residing at the location you thought it was. These “heartbeat” methods just allow consumers to check for signs of life, verifying that the service exists.
The heartbeat shouldn’t require any particular parameters or any authentication, since formatting data and passing credentials can be a stumbling block for those integrating with a service for the first time or those debugging issues. The heartbeat method can return some known data, perhaps an “I’m here” message, and maybe some version information. Flickr has a nice method flickr.test.echo which will also echo back any parameters that were sent to it – which could be useful for debugging values which don’t arrive at the server as you expected.
Another use for a heartbeat method is to allow monitoring systems to call a simple method, needing no credentials, and always get the same response back. Its not uncommon for these monitoring systems to be pointed at a particular page, and for failures to be indicated if the contents of that page changes (because data in the system changes, for example).
So – build a heartbeat service, you might never use it but when you need it, you’ll be glad you did!
Adding PUT variables to Request Object in Zend Framework
Its very simple: I have extended Zend_Controller_Action with my own, and all controllers inherit from here. This has a routeAction() which grabs the incoming variables from a PUT request and sets them as parameters within the usual $this->getRequest() scope, then forwards on the request. Here is my class:
class My_Controller_Action extends Zend_Controller_Action
{
public function routeAction()
{
// handle grabbing PUT vars
if($this->getRequest()->isPut()) {
parse_str($this->getRequest()->getRawBody(), $params);
foreach($params as $key => $value) {
$this->getRequest()->setParam($key, $value);
}
}
$this->_forward(strtolower($this->getRequest()->getMethod()));
}
}
So in my controller code, I simply call out to $this->getRequest()->getParam(‘name’) or whatever, and in my tests I can set those parameters as I showed in my other article.
I hope this makes sense, its one of those things I set up once and use a lot (and now I’ll be able to refer to how I did it!), if you have any queries, comments, improvements or if this helps you then please leave a comment – I haven’t come across anyone else doing anything similar but I know there must be, so let me know!
Using Zend_Test for Web Services
Using Zend_Test, I set up the request object I wanted to send, and dispatched it. Then I retrieved the body and, since this service returns JSON, I json_decoded it. This gives me an object – and I can go ahead and use all the functionality of PHPUnit, with or without Zend_Test’s additions, to test my service. Its perhaps easiest to show this in a few steps.
Setting up the request object
The idea here is that you set up any parameters you need to including the HTTP verb to use and cookies if needed, then despatch the request. Here’s a few examples, first a simple GET method, with a cookie.
$request = $this->getRequest();
$request->setMethod('GET');
$request->setCookie('token','xxxx');
$this->dispatch('/user/24');
Including data with a POST request:
$request = $this->getRequest();
$request->setMethod('POST');
$request->setPost(array(
'name' => 'new user',
'organisation' => 49
));
$this->dispatch('/user');
This is a REST service, so I also tested PUT and DELETE methods. DELETE just needs the setMethod() call since it doesn’t have any data with it, but PUT was a bit trickier – here’s an example of what I used:
$request = $this->getRequest();
$request->setMethod('PUT');
$params = array('name' => 'Harry Potter');
$request->setRawBody(http_build_query($params));
$this->dispatch('/user/48');
Decoding the Response
This is the easy part, all I do is check the status code is what was expected, and then decode the response. My web service returns JSON so this part of each test looks something like:
$this->assertResponseCode('200');
$response = json_decode($this->getResponse()->getBody());
Testing the content of the response
Here we get into classic PHPUnit territory and simply use the assertTrue and assertEquals calls we’d use when testing anything else, an example is included for completeness:
$this->assertEquals($response->contentType, 'user');
$this->assertTrue(is_numeric($response->id));
$this->assertEquals($response->name, 'new user');
$this->assertEquals($response->organisation, 49);
In Conclusion
By combining the request/response awareness of Zend_Test with standard PHPUnit testing strategies, its easy to test web services as well as web pages. I hope the examples are helpful – if they help you or if you have anything to add, then leave a comment!