Yahoo API search with JavaScript alone

October 12th, 2006. Tagged: JavaScript, JSON, yahoo

Previously I've mentioned how I do image searches with my bigger daughter, hunting for images of Cinderella, Ariel the little mermaid, and other equally beautiful princesses. So I thought why not build a custom little app for the little kid to do this, I mean, her, being the good (and beautiful) girl that she is, totally deserves it. Here are the very basics of such an app, my idea was to do a little demo how you can consume Y! services to do web and image searches, using nothing but JavaScript. Look ma, no server! ;)

» demo

JS alone

The cool think about Y! web services is that they provide you different options for the output format of the results they return. You can get XML, php serialized string or JSON. (No SOAP, thank you very much!). I think more companies should consider such an offer, I mean since you get your service to work, the output format is just a ... a format, nothing special.

How do you make the request? With JavaScript includes, meaning you use DOM methods to sreate a new <script> tag and add it to the head of your page. The src attribute of the new script tag points to the Y! service, a longish kind of URL with a bunch of parameters.

When making your request, you say that the output format should be JSON. Then you provide a callback function name. What Y! service does is it calls the function you gave, passing the JSON output as a parameter. Let's say you made a request to:

http://..../...&output=json&callback=myfunction

and we assume the result of your request is an array:
[1,2,3]
The Y! service will write out:
myfunction([1,2,3])
At the end, your function gets called, receiving the response from the call to the Y! service. It's now up to this function to decide what to do with the result.

Implementation

It all starts with a simple form and a placeholder for the result:

<body>
<form
    action=""
    method="get"
    onsubmit="ysearch.doSearch(
                this[0].value, 
                'content', 
                this[1].checked
              ); 
              return false;">
  <input />
  <input type="checkbox" />Image search
  <input type="submit" value="go!"/>
</form>
<div id="content">&nbsp; </div>
</body>

Submitting this form calls the doSearch() method of the ysearch class.

ysearch class has a few properties:

// url of the image search service
this.image_url = "http://api.search.yahoo.com/ImageSearchService/V1/imageSearch?";
// url of the web search service
this.web_url = "http://api.search.yahoo.com/WebSearchService/V1/webSearch?";
 
// ID of element that will
// display the result
this.where = '';
// is this an image search?
this.image_search = false;
 
// parameters for the search
this.url = "output=json"+
           "&callback=ysearch.process" +
           "&appid=YahooDemo" +
           "&start=1" +
           "&results=5" +
           "&query=";
 
// reference to the last included script
this.last_include = false;

Then comes the doSearch method. It does the following:

  1. Checks input parameters to see if this is a request for a web search or an image search. The two types af searches use a different web service with a different URL
  2. Appends the search query to the URL
  3. Creates a new script tag with SRC that was just figured out
  4. Saves a reference to the new script tag, so that it can be cleaned up with the next search

Here's the actual code for the doSearch() method:

this.doSearch = function(q, where, web_image) {
 
  this.where = where;
 
  var script_filename = "";
  if (web_image) {
      script_filename = this.image_url;
      this.image_search = true;
  } else {
      script_filename = this.web_url;
      this.image_search = false;
  }
 
  script_filename += this.url + escape(q);
  var html_doc = document.getElementsByTagName('head').item(0);
  // remove the last included script, we don't need it anymore
  if (this.last_include) {
      html_doc.removeChild(this.last_include);
  }
  var js = document.createElement('script');
  js.setAttribute('type', 'text/javascript');
  js.setAttribute('src', script_filename);
  html_doc.appendChild(js);
 
  // set the pointer to the last include
  this.last_include = js;
 
};

Becuase we passed the callback function name ysearch.process to the service, the new Y! script will call it, passing the search results as an object. Let's see what process() does, really nothing but looping through the results object (description of the object here and here) and spitting out HTML using the politically incorrect innerHTML. Here's the code:

this.process = function(resp) {
 
  if (resp.ResultSet && resp.ResultSet.totalResultsReturned > 0) {
    // loop through the results
    var out = '';
    for (var i = 0,
     max = resp.ResultSet.Result.length;
     i < max;
     i++) {
 
    var item = resp.ResultSet.Result[i];
    if (this.image_search) {
      out += '<p><a href="' + item.Url + '">'
      out += '<img src="' + item.Thumbnail.Url + '" /><\/a>';
      out += '<br />' + item.Summary + '<\/p>';
    } else {
      out += '<p><a href="' + item.Url + '">' + item.Title + '<\/a>';
      out += '<br />' + item.Summary + '<\/p>';
    }
 
    }
    document.getElementById(this.where).innerHTML = out;
  } else {
    alert('no results');
  }
}

Tell your friends about this post: Facebook, Twitter, Google+

Sorry, comments disabled and hidden due to excessive spam. Working on restoring the existing comments...

Meanwhile, hit me up on twitter @stoyanstefanov