All Posts Tagged With: "Web Services"

REST Web Services, the Book

Sam Ruby and Leonard Richardson are writing a book on REST Web services. Very exciting. I love reading Sam’s blog and watching him untangle standards.

Looking at the Table of Contents, I’m particularly interested in “Appendix A: HTTP status codes and when to use each one.” (Yes, I am serious.)

eBay SOAP Update: Syntax Matters

I saw a request for some actual SOAP code, so I will try and oblige. I don’t want to publish the entire code because there’s lots of messy stuff that’s specific to eBay’s SOAP API. I’ll talk about that some other time, but for now, those details just get in the way.

Therefore, I’ll pull out a few lines, combine that with some hand waving, and just hope for the best. Here’s the before:


$wsdl = 'http://developer.ebay.com/webservices/latest/eBaySvc.wsdl';
$client = new SoapClient($wsdl);


$params = array('Query' => 'ipod');
$results = $client->GetSearchResults($params);

foreach ($results->SearchResultItemArray->SearchResultItem as $item) {
  print $item->Item->Title . "\n";
}

Without the classmap option, I create a SoapClient, make my request, and then iterate through the results to print out the titles of the matching items. This isn’t complex; however, the iteration is a little klunky due to limitations of SOAP and the design of eBay’s Web service.

For example, the SearchResultItemArray only contains SearchResultItem, so it’s kludgy to reference SearchResultItemArray->SearchResultItem. Likewise, when I’m just getting a quick dump of Item information, it’s not so nice to specifically access the Title element.

By defining a couple of classes and telling the SoapClient object map them to the return data, I can clean this up:


class eBaySearchResultItemArrayType implements IteratorAggregate {
  public function getIterator( ) {
    return new ArrayObject($this->SearchResultItem);
  }
}

class eBaySearchResultItemType {
  public function __toString() {
    return $this->Item->Title . "\n";
  }
}

$wsdl = 'http://developer.ebay.com/webservices/latest/eBaySvc.wsdl';
$options = array('classmap' => array(
  'SearchResultItemArrayType' => 'eBaySearchResultItemArrayType',
  'SearchResultItemType' => 'eBaySearchResultItemType',
  ),
);

$client = new SoapClient($wsdl, $options);

$params = array('Query' => 'ipod');
$results = $client->GetSearchResults($params);

foreach ($results->SearchResultItemArray as $item) {
  print $item;
}

To solve my first problem, the iteration, I make eBaySearchResultItemArrayType implement the IteratorAggregate interface. When a PHP 5 class implements this interface, PHP will invoke the getIterator() method during a foreach loop.

In this case, I return $this->SearchResultItem, wrapping it inside an ArrayObject to make the array iterable.

For the pretty-printing issue, I define a __toString() method inside of eBaySearchResultItemType. Now, when I print an instance of this class, PHP calls that method instead.

With my classes defined, I use the classmap option to map the PHP classes to the SOAP complexTypes, and pass this mapping along as part of the second parameter to the SoapClient constructor.

Once this is set up, everything else in the request is identical. However, when I print out the results, the syntax is clean:


foreach ($results->SearchResultItemArray as $item) {
  print $item;
}

At one level, this is just syntax and icing. However, I don’t think you should dismiss syntax with a wave of your hand. To quote Sam Ruby on C# and LINQ:

[S]yntax matters. Very much so.

So, I am convinced that this is a good thing to spend time on. There are a couple other tricks I’ve pulled out, such as:


class eBayFeesType implements ArrayAccess {

  public function offsetGet($offset) {
    foreach ($this->Fee as $value) {
      if ($value->Name == $offset) {
        return $value;
      }
    }
  }

  /* and the other interface methods... */
}

class eBayFeeType {
  public function __toString() {
    return (string) $this->Fee->_;
  }
}

This lets me do:


echo "Listing fee is: ", $results->Fees['ListingFee'], "\n";

Which I must say is far nicer than either iterating in place or even calling out to a utility method.

I was interested to discover that I needed to manually cast $this->Fee->_ to a string because I thought it was a string. Actually, it is a float, and PHP won’t autocast floats to strings in this instance.

Personally, I think if PHP should autocast here, but I can see the logic. If you’re promising to return a string, you should actually return one.

At first, I was writing each class by hand. But that got boring and wasn’t scalable. Therefore, my new goal is to automate this process. I am writing a script to read the WSDL file, parse out the complexTypes, and then convert them to PHP classes.

My original script was using the SoapClient::__getTypes() method as a pre-processor, but I needed to parse that output again to get it into a usable format. After a little digging, I discovered that PEAR::SOAP implements its own parsing routines and gives me a far more flexible PHP data structure to manipulate. So, I am going in that direction instead.

Since this is a one-time action, speed isn’t vital, so it’s okay that PEAR::SOAP is written in PHP.

If you’re interested in more details on these new PHP 5 features, they’re documented in the PHP Manual. Alternatively, in a shameless plug, you can check out my book Upgrading to PHP 5.

Programming eBay Web Services with PHP 5 and Services_Ebay

My latest article is now available on the O’Reilly Network. "Programming eBay Web Services with PHP 5 and Services_Ebay" provides an introduction to eBay Web services and Stephan Schmidt’s awesome PEAR package, Services_Ebay.

As I’ve blogged before, Services_Ebay is a PHP 5-only module that makes it drop dead simple to interact with eBay Web services. This piece walks you through getting started with Services_Ebay, shows you how to search the eBay listing database, and then displays the found items in a variety of ways.

As a extra special bonus, I highlight all the cool behind-the-scenes PHP 5 magic that’s taking place. I also do some nifty stuff by overriding Stephan’s model classes to provide an alternative data view. I’m sure this will lead to nasty comments from the peanut gallery about my lack of respect for MVC.