zach graves

my unimportant thoughts

Using YQL with Yahoo! Weather

without comments

YQL is seriously awesome.

If you haven’t heard of YQL yet, think of it like this… Yahoo! (and the rest of the internet) turned into a huge query-able database, letting you filter, combine and sort through the returned data.

YQL has a simple SQL-like syntax that takes no time to get familiar with. So… let’s see some queries.


select * from rss where url='http://rss.news.yahoo.com/rss/topstories'

http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20rss%20where%20url%3D’http%3A%2F%2Frss.news.yahoo.com%2Frss%2Ftopstories’&format=xml

This simply pulls in an RSS feed, and returns the result. One of the cool things is that you can request a JSON response instead of the original XML format of the feed, just by changing the format param. This makes it so much easier to work with in my opinion.

http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20rss%20where%20url%3D’http%3A%2F%2Frss.news.yahoo.com%2Frss%2Ftopstories’&format=json

So… what can you really do with this? Good question. YQL also allows you to access social data from within Yahoo. So if you start combining all these services together you can get some pretty cool results.

Let’s take this scenario. I have a user in my Yahoo! app and I want to show their current weather conditions. There are a few data points you need to get in order to get this information from the Yahoo! Weather API. First off, you need the users location, found in their profile. A simple query to YQL will get you that field.


select location from social.profile where guid=me


"results":{
  "profile":{
    "location": "seattle, washington"
  }
}



Next up, because the location can be pretty ambiguous, we need to try to convert it to a more structured format. We can go this using the Y! GeoPlanet APIs.


select locality1,country from geo.places where text = "seattle, washington" limit 1


"results": {
  "place": {
    "country": {
      "code": "US",
      "type": "Country",
      "content": "United States"
    },
    "locality1": {
      "type": "Town",
      "content": "Seattle"
    }
  }
}



Now we have some better data, which will work for international locations as well. Now, you may think its time to query Y! Weather, but the next step will be to convert the location into a weather location ID. This is needed because Y! weather only accepts US Zip Codes and Location IDs; and in many cases you may find that the accuracy of the users location does not produce a zip code, and international locations won’t either.

Luckily, weather.com has a nice API that allows you to search for IDs.


select loc.id from xml where url='http://xoap.weather.com/search/search?where=Seattle,United+States' limit 1


"results": {
  "search": {
    "loc": {
      "id": "USWA0395"
    }
  }
}



Aha, there’s our ID.

Lastly, just use that ID to query Y! weather.


select * from weather.forecast where location="USWA0395"


"results": {
  "channel": {
    "title": "Yahoo! Weather - Seattle, WA",
    "link": "http://us.rd.yahoo.com/dailynews/rss/weather/Seattle__WA/*http://weather.yahoo.com/forecast/USWA0395_f.html",
    "description": "Yahoo! Weather for Seattle, WA",
    "...",
    "..."
  }
}



But wait! There’s more!

Remember I said you could combine data?

You can squash all these queries down into only two queries!


select locality1,country from geo.places where text in (select location from social.profile where guid=me) limit 1


$q = $locality1.",".$country;



select * from weather.forecast where location in (select loc.id from xml where url='http://xoap.weather.com/search/search?where=$q' limit 1)



Now, to put this into some real-world code, if you are using our PHP SDK, you can get all this in only a few lines of code.


include "yos-lib/Yahoo.inc";

$session = YahooSession::requireSession($consumerKey, $consumerKeySecret, $applicationId);

$loc_yql_rsp = $session->query("select locality1,country from geo.places where text in (select location from social.profile where guid=me) limit 1");
$loc = $loc_yql_rsp->query->results->place;

$q = $loc->locality1->content.",".$loc->country->content;

$weather_yql_rsp = $session->query("select * from weather.forecast where location in (select loc.id from xml where url='http://xoap.weather.com/search/search?where=$q' limit 1)");
$user_weather = $weather_yql_rsp->query->results->channel;

print_r($user_weather);



Written by zachgraves

December 18th, 2008 at 2:22 am

Posted in Uncategorized

DOUBLE_CLICK

without comments

Just noticed I still have this problem. Back when I was working on the AS3 Maps API, I ran into this and brought it up with Ted one day while we were in a conference room together at Adobe.

Check this out:


package
{
	import flash.events.MouseEvent;

	public class MySprite extends Sprite
	{
		public function MySprite()
		{
			super();

			init();
			addListeners();
		}

		private function init():void
		{
			this.graphics.beginFill(0xFF0000,1);
			this.graphics.drawRect(0,0,15,15);
			this.graphics.endFill();

			this.buttonMode=true;
			this.useHandCursor=true;
			this.doubleClickEnabled=true;
		}

		private function addListeners():void
		{
			this.addEventListener(MouseEvent.CLICK, handleClick);
			this.addEventListener(MouseEvent.DOUBLE_CLICK, handleDoubleClick);
		}

		private function handleClick(event:MouseEvent):void
		{
			trace(event.type);
		}

		private function handleDoubleClick(event:MouseEvent):void
		{
			trace(event.type);
		}

	}
}

Trace output after ONE quick double click action:

click
doubleClick

Weird.

Written by zachgraves

October 17th, 2008 at 4:05 am

Posted in ActionScript

Tagged with

flash.net.*

with one comment

I’ve been struggling lately with Flash.

Specifically with the weakness in working with REST within flash.net.*. I’m not talking about Flex, I could use HTTPService. My use is for a new AS3 lib for the Yahoo! Social APIs which rely heavily on request headers & request methods, response codes & response headers. Each of these present their own difficulties in implementing a developer API in pure AS3.

Take for example a request to the Yahoo! Status API. A URL typically looks like this:

GET http://social.yahooapis.com/v1/user/{guid}/presence/presence

This request should be signed by OAuth, where the recommended approach to this is supplying these credentials in an Authorization header. Doing this in Flash is difficult because if you wish to GET the users status in this case, you can’t send any headers in a GET. The work-around here is to just add the OAuth parameters into the query string.

GET http://social.yahooapis.com/v1/user/{guid}/presence/presence?oauth_signature=foo&oauth…

If you want to update the user’s status, you would make a similar request.

PUT http://social.yahooapis.com/v1/user/{guid}/presence/presence
{
“status”: “writing a blog post”}

Simply put, flash.net.URLRequest does not support a PUT, HEAD or DELETE request in Flash Player, only in AIR. So, I was not able to implement a ’setPresence’ or ‘insertUpdate’ method in the API unless it was only available within an AIR container (maybe in a later version)

Once you make a request to the server, in most cases you are unable to access the response code. On my Mac, both Safari and Firefox don’t provide response codes to Flash, so its impossible to tell the difference between a 200 OK, 401 Authorization, 403 Forbidden or 404 Not Found errors. Instead you’re left with only the Event.COMPLETE and IOErrorEvent.IO_ERROR events to discern between success and failure; you never know what the response code actually is in most browsers. (I always get zero)

Next, response headers are non-existant in Flash Player. So for example, if a request to the Yahoo! APIs results in a 401 Authorization error, its not possible to read the WWW-Authenticate header which in my case provides information on what went wrong.

At one point I went down the path of building an HTTPSocket class which morphed a Socket into a URLLoader like object- but hit a wall when I realized that the hoops I’d have to jump through to get it working under the recent security changes in Flash on the server-side, which I don’t have free access to.

I realize that some of these issues are due to limitations of the networking stack in the plug-in within the browser. However, I think these issues present some big holes in Flash for any developer who wants to work with RESTful (or even OAuth enabled) APIs, I hope that Adobe can push to get some of these issues fixed in a future version of Flash Player.

Bugs:

http://bugs.adobe.com/jira/browse/ASC-3382 (flash.net.URLRequestMethod does not support all http verbs - marked as ‘not a bug’)
http://bugs.adobe.com/jira/browse/FP-251 (Access HTTP Response Headers - open)
http://bugs.adobe.com/jira/browse/FP-721 (URLLoader - HttpStatusEvent should return a valid http status code and not 0 - open)
http://bugs.adobe.com/jira/browse/SDK-11401 (URLoader ignores header values when using URLRequestMethod.GET - closed)

Written by zachgraves

October 15th, 2008 at 12:08 am

Posted in ActionScript

Tagged with , , , ,