Web Services

Yahoo! Search Web Services

Yahoo! Search has just launched a Web service:

http://developer.yahoo.net/

You can search five databases: web, local, news, image, and video.

It’s completely free to use for all personal and non-commercial projects and it’s totally REST-based. No SOAP.

There’s an SDK. It’s released as open source under the BSD license.

http://developer.yahoo.net/download/

There are examples in all the major languages: Java, JavaScript, Perl, PHP, and Python.

They’re hosting applications on a Wiki:

http://developer.yahoo.net/wiki/index.cgi?ApplicationList

So far, there’s a Firefox Sidebar and an Image search application.

More links and information:

The Future of TiVo

Jeffrey and Greg have been engaging in a spirited discussion on the future of TiVo. To help keep the debate going, I pass along, without comment, this article in today’s SF Chronicle.

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.

Using the Google AdWords API with ext/soap

On Friday, Jeffrey showed me Nelson’s new Google AdWords API service. Google has now exposed all parts of the AdWords program via a SOAP Web service API.

Unfortunately, SOAP and PHP still aren’t the best of friends. True, Nelson has graciously provided us with some NuSOAP PHP example code. However, when I viewed it, I immediately barfed all over myself. Gross!

Any SOAP library that requires you to use angle-brackets is missing the point of SOAP. To be fair, I’d never used NuSOAP before today, so maybe it’s possible to rewrite the code to be more elegant, but I couldn’t stomach trying.

I mean, come on. This is no way to set a SOAP header:

// Set up the authentication headers
$email = "<email>youremail@your company.com</email>";
$password = "<password>yourpassword</password>";
$userAgent = "<useragent>YOURCOMPANY -- PHP KeywordReport Demo</useragent>";
$token = "<token>developer_token_here_</token>";
$header = $email . $password . $userAgent . $token;

And comments like this?

// With nusoap, you need to include XML with the parameters
$keyword0 = "<text>flowers</text>";
$keyword1 = "<text>chocolates</text>";
$otherinfo = "<maxCpc>50000</maxCpc><type>Broad</type>";

I need to include XML?!? Forget it.

So, out of the spirit of being a good citizen, I rewrote the "Estimating traffic for a keyword" example using PHP 5’s ext/soap extension.

// Connect to the WSDL for the TrafficEstimatorService
$wsdl = "https://adwords.google.com/api/adwords/v2/TrafficEstimatorService?wsdl";
$client = new SOAPClient($wsdl));

// Create the SOAP Headers for authentication
$ns = 'https://adwords.google.com/api/adwords/v2';
$email = new SOAPHeader($ns, 'email', 'adam@trachtenberg.com');
$password = new SOAPHeader($ns, 'password', 'XXX');
$useragent = new SOAPHeader($ns, 'useragent', 'Blah, blah');
$token = new SOAPHeader($ns, 'token', 'XXX');
$headers = array($email, $password, $useragent, $token);

// The Keywords we're interested in
$keywords = array(array('text' => 'php', 'maxCpc' => 100000, 'type'=> 'Broad'),
                  array('text' => 'mysql', 'maxCpc' => 250000, 'type' => 'Broad'),
                 );
try {
  // Make the request to estimate the keywords
  $response = $client->__soapCall('estimateKeywordList',  array($keywords), null, $headers);

  // If we got this far, $response contains the estimates
  $count = count($response->estimateKeywordListReturn);
  echo "<P>There are " . $count . " elements in the response array.";

  // A single  response is returned as an array of field values.
  // Multiple responses are returned as an array of arrays.
  if (! is_array($response->estimateKeywordListReturn)) {
    $response->estimateKeywordListReturn = array($response->estimateKeywordListReturn);
  }

  for ($i = 0; $i < $count; $i++) {
    // Need to get the keyword text out of $keywords array
    // because the keywordEstimate doesn't know the keyword text
    echo "<H3>" . $keywords[$i]['text'] . "</H3>";
    printResults($response->estimateKeywordListReturn[$i]);
  }    
} catch (Exception $e) {
  // Barf
  print $e;
}

function printResults ($estimate) {
  echo "<blockquote>cpc " . $estimate->cpc; 
  echo "<br>clicks " . $estimate->ctr * $estimate->impressions;
  echo "<br>ctr " . $estimate->ctr; 
  echo "<br>impressions " . $estimate->impressions;
  echo "<br>notShown " . $estimate->notShownPerDay;
  echo "<br>position " . $estimate->avgPosition;
  echo "</blockquote>";
}

No more XML. Still a little kludgy because of the SOAP headers, but overall much nicer.

In the process, I found a bug involving SOAPHeader objects when you don’t want your data to live inside a namespace, but I managed to work around that by placing them inside the AdWords API namespace.

I was also thrown a little bit by the example, which places the keywords inside a “KeywordRequest” element, when the WSDL seems to want a “keywordRequests” element. (Note different capitalization and pluralization.) This had me running down all sorts of dead ends and blaming the WSDL parser.

Last, I’m confused why the server doesn’t return the keywords back to me. Forcing me to map the input and the output is a little kludgy.

Overall, however, this looks quite nice. I plan on playing around with it more later, and I’m sure our eBay API Affiliates are having a field day.

Services_Ebay

My man Stephan Schmidt just released the first version of a kick ass eBay API PEAR package for PHP. Our XML Web services API is pretty easy to use technically, but we don’t go a great job integrating all 70+ API calls into a coherant structure.

When Stephan designed Services_Ebay, he took a step back and looked at how all the different calls should play together. This allowed him to implement a very slick object-oriented package that makes it simple to use eBay from PHP.

There are still a few tricky bits to figure out, but I’m quite impressed with what he’s done so far. Check it out. It uses lots of new PHP 5 features, such as __call() and iterators, to simplify the code, so it’s a great way for you to look at why you should be Upgrading to PHP 5. (Okay, I couldn’t resist the plug.)

World Tour: Utah PHP

Do you love PHP? Do you love eBay? Do you live in Utah? If you answered “yes” to all three questions, then you don’t want to miss the next stop on my world tour.

Next Tuesday, October 19, I will be visiting the Utah PHP Users Group to give a talk on Developing Applications on the eBay Platform with PHP. Start time is 7 PM and we’ll go until 8:30.

O’Reilly has arranged to send a carton-load of books, and I will be bringing a bag full of eBay schwag, so they’ll be giveaways gallore!

Web 2.0

In case you’re interested in Web 2.0, Jeremy Zawodny is blogging up a storm.

Success! eBaySOAP class almost ready

After a Titanic struggle, I have managed to make a successful SOAP call to eBay using PEAR::SOAP. I’m in the process of cleaning up my code, but once it’s all nice, I’ll release version 0.1 of eBaySOAP.

Right now PHP 5 is a requirement, since I ended up aggregating the SOAP client inside a PHP class to make things easier for developers. For some reason, PEAR::SOAP isn’t setting a namespace for our parameters, so I need to intercept any parameters and create SOAP_Value objects for them with the proper namespace. If I use __call(), I can step in and do this transparently and you’re none the wiser.

I bet I can backport this to PHP 4, if I use the overload extension. It shouldn’t be too hard, especially as I’m using the PHP 4 version of PEAR::SOAP.

I also had to make a small patch to PEAR::SOAP. Right now, if PEAR::SOAP sees a namespace with a colon (:) in it, it presumes it’s a qualified name (qname for short) of the format prefix:localpart. In eBay’s case, we have a namespace of urn:ebay:API:eBayAPI. This isn’t a qname, but PEAR::SOAP thinks it is and incorrectly breaks it apart. My patch checks to see if the namespace beings with urn: and tells PEAR::SOAP to ignore it.

I need to do some digging to see exactly why PEAR::SOAP does this and why it doesn’t break namespaces that look like URLs also.

So, next steps:

  1. Clean up code and release eBaySOAP.
  2. Submit patch to PEAR::SOAP.
  3. Backport eBaySOAP to work with PHP 4.
  4. Investigate PHP 5 version of PEAR::SOAP.
  5. Investigate ext/SOAP extension in greater detail. I’ve done some preliminary work here, but I’m finding bugs and they’re hard to fix at work since I’m using Windows.
  6. Look to patch PEAR::SOAP to automatically add the correct namespace to parameters, so I don’t need to do it myself.
  7. Write up an article, so everyone can learn how cool eBaySOAP is.
  8. Profit!

If you’re interested in this topic, please add your feedback below, so I can use it to guide my to do list.