Tuesday, April 1, 2014

Part 26 Retrieving a Photo from Flickr's PI [AbsoluteBeginnersSeriesForWindowsPhone8_files]


In this lesson we'll search for Flickr photos near the geocoordinate determined by our
phone.

Many of the most popular phone apps have some interaction with web-based services
... so the app allows users to get at their own data that they've stored "in the cloud", or
they provide access to data in order to make it available in some fresh new way.

As developers, we can access the web-based services programmatically IF they expose a web API. A web API is usually just an HTTP based method call ... the URL includes the input parameters of the method call, and the web API will return data back in some standard format. Nowadays, that is usually XML or JSON, JavaScript Object Notation.

Flickr is a great example of a web service we can leverage in our apps ... They have a
vast amount of image data that we can search via their web-based API. All we need to
do is call one of their methods and then parse the data they return to us.

Our game plan in this lesson:

1.  We'l  do a little investigation into the Flickr API to see how we can leverage it in our app 
2.  We'l  get setup with Flickr so that we can make cal s to their API, and get examples of how to call the method we want to utilize 
3.  We'l  write code in our app to make calls to the Flickr API 
4.  When we get data back from our call to the Flickr API we'l  figure out how to parse through it and actual y obtain pictures that we can display in our app

This is a VERY long lesson, but it's crucial because it will serve as a proof of concept
that our idea will actually work. We'll see how all the pieces come together and then the
rest of the series will be adding improvements and refinements to what we do in this
lesson.

1. Become familiar with the flickr API site, sign up for developer access

This is the home page for Flickr's API.


Before you can take advantage of the API in your app, you'll need to sign up for a
developer account.

There should be an obvious Sign Up link somewhere on the top of the page. I won't
walk through that process ... it's likely to change over time. I was able to use my existing
Yahoo! ID to sign up for a developer account. It's free and easy to get started, and you'll
need your own account so that you can get your own API Key.


Most companies exposing APIs over the web want to ensure that developers are
complying with their terms of service, or they want to track usage by app to better
understand how their APIs are being leveraged. I suppose in extreme cases the
company may want to shut down an app that is abusing the service. This is why most
require a unique identification for the developer and the app through the use of an API
Key. Flickr is no different.

To get an API Key for the AboutMe app, find the "API Key" somewhere on the Flickr API homepage.


This will list all of the API Keys you were granted for your apps. You'll need to use a
different API Key for each app you intend to use with Flickr's API.

Ultimately, you want to create a new API Key by using the "Get Another Key" button.


For now, our app will not make any money, or it's not currently commercial but might be
in the future, so choose "Apply for a Non-Commercial Key":


They want to learn more about the app you're building. You can copy my text if you
want. You'll also need to agree to the terms and such:


When you fill out the form and click the SUBMIT button, you should receive your API
Key.

Since I'm (probably) not supposed to legally reveal my key, I've blurred some of it out.
Keep the Key and the Secret available. We'll need them later in this lesson.


Back on the main Flickr API page, you see a list of all the web callable APIs available
on Flickr. You can literally perform any conceivable operations using Flickr as the
backend storage and processor for your photos and create new applications that "mash up" Flickr's functionality with some of your own. That's exactly what we want to do ... combine Flickr's search capability for photos -- specifically searching for photos that
were taken geographically in the same place the user of our app.

We want to learn more about the flickr.photos.search API ... how do we call it? What
options can we send along to specify geolocation we want to search for?

2. Learning about Flickr's search API


When you find the API you're looking for (i.e., flickr.photos.search), click the hyperlink to
learn more about that web API method.


On this page dedicated to the flickr.photos.search web method, we can see which input
parameters are optional and which are required, the purpose / meaning of each
parameter, the expected format of the parameter value, and so on.

We also can see a list of error codes returned by the web method to the caller ... this
might help us interpret any error codes we receive.



There's also an "API Explorer : flickr.photos.search" link which takes us to a web page
where we can experiment and learn how to call that particular web method.


By clicking the "Send" check box and supplying a value, we can see the format that our
web method call should take. I'll input the a number of options such as the optional
latitude and longitude for the John Hancock Center, and add optional text "observatory":


I'll add an optional radius of "1". I learn that the default "radius_units" are in kilometers,
so by adding a "1" I'm saying "search within a 1 kilometer radius of the geocoordinate
I'm specifying".

I also will choose to send the output of my query to JSON, the JavaScript Object
Notation.

I'll choose the radio button next to "Sign call with no user token".

Once I've added my settings, I'll click the "Call Method..." button.


When I click the "Call Method..." button, a large textbox will appear beneath the button
containing sample data in JSON format, as well as the URL that was constructed based
on my selected options. Both of these will be important for me in just a moment.


3. Setting up our project to use the Flickr API
Back in my Visual Studio project, I'll need to prepare for making my first call into the
Flickr API. I'll want to appropriately brand the app by changing the app and page titles.
I'll just hardcode them this time and not use the resources file. I realize this will limit my
app to just English speakers. I can always come back later and change this.



1.  Change the Text attribute to "AROUND ME" 
2.  Change the Text attribute to "pictures near ..."

My next changes will be in the ContentPanel.


1.  Add three RowDefinitions at various heights 
2.  Put a control in each of those new rows. I create a TextBlock called ResultTextBlock" for row 1. I create an Image control called "FlickrImage" for row 
3.  Move the Map to row 3.

4. Programmatically calling the Flickr API via HTTP
My goal is to populate the Image control with a single image. Later, I'll add a search
results page that can display all the results. For now, I just want to hack something
together to figure out how to call into the Flickr search API programmatically and get
results. I'll make it work correctly later.



1.  I comment out the SetView() and instead use the Map's Center and ZoomLevel
properties just to show how to perform the same task using only the 
2.  The ResultTextBlock should not be here 
3.  I want to make a call via the web and I know there's a class in the Windows Phone 8 API
called HttpClient. However, I don't have that package installed in my project.

I can find that package on NuGet at: http://nuget.org/packages/Microsoft.Net.Http


NOTE: Since I took this screenshot, this package no longer requires the -Pre argument.

I pay particular attention to the way you install the package using the Package Manager
Console: Install-Package Microsoft.Net.Http

To open the Package Manager Console:


1.  Tools menu 
2.  Library Package Manager 
3.  Package Manager Console

This will open the Package Manager Console by default in the bottom area of Visual
Studio (unless you docked it somewhere else in a previous session).

You'll type in the install-package command at the Package Manager prompt: Install-
Package Microsoft.Net.Http


If all goes smoothly, you'll see the a number of messages appear indicating success:


Now when you look at the Solution Explorer under the References folder, you'll see
three new references System.Net.Http.*


Now we should be able to resolve the reference for the HttpClient class. However your
mouse cursor over the blue dash under the "H" in HttpClient to reveal a drop-down
menu. Choose the: using System.Net.Http;

... option to add a using statement to your MainPage.xaml.cs.


Now I work my way through the process of building a URL to call Flickr's search web
API. I'm using that URL from the "API Explorer" as my template, substituting the
optional parts like the api_key, license, lat, lon and so on.


1.  First I add licenses that I want to search through. I only want to include licenses that have limited or no copyright licenses associated with them to avoid any legal problems. I could hardcode this string, however I would prefer to construct it so that I could modify it easier and more consistently in the future. As you can see I'm switching out the commas in this string for %2C ... this is a form of URL Encoding. Leaving certain punctuation in aURL like commas, periods, quotation marks, question marks, ampersands and so on could produce unpredictable results because they have a specific meaning and usage when the URL is parsed by the web server. So, to bypass that, we URL encode those characters. After the web server software is finished parsing the URL, those characters wil  be decoded and understood the way we want them to be understood. It's a form of packing and unpacking a suitcase that you'l  take on a flight with you. 
2.  Here I've separated out my Flickr API Key because I may want to replace it later. 
3.  Here I create the URL as a string with the replacement codes -- like {0} and {1} -- for use in the next line of code ... 
4.  Here we use string.Format to perform the replacement of the code -- {0} and {1}, etc. -- with the actual values we'l  use for the web api call. 
5.  Here we actual y make the call to Flickr by passing our newly constructed URL to the HttpClient's GetStringAsync() method. When it returns, we'l  display it in the TextBlock I added earlier. I do this so I can actual y see what we're getting back from the web service.

Let's run the app (F5) and see what we have so far:



What we get back from Flickr is a string of JSON as we expected. 

5. Deserializing the JSON result into classes
We will need to convert that string of JSON into something we can use, like CLR types
(or rather, classes). There's a little trick for this that I learned from Clint that will create
classes that represent the data structures used in the JSON so that we can deserializeit into instances of those classes. Once we have the JSON data into a class hierarchy,
we can work with it in C# quite easily. 

First, we'll need to grab the actual JSON that has been returned by the web service call
to Flickr.

I set a breakpoint on the line of code where we set the ResultTextBlock's Text property
to the result from Flickr:


And then I run / debug (F5) the app. When we get to that breakpoint, I hover over the
flickrResult variable to see the data. If I click on the little magnifying glass icon next to
the data I get a menu that will allow me to see the data in one of several visualization
dialog windows:


Choosing "Text Visualizer" will open the Text Visualizer dialog. Here, I can copy all of
the JSON on to my clipboard:


... and now that I have that JSON copied to my clipboard, I navigate to:


... and paste the JSON into the large text box on that page, and click the Generate
button:




Beneath the Generate button, I get the output: C# classes that match the JSON data
structure. Quite awesome!

I click the "Copy" button ...


... and click Ctrl + C to copy the C# code to my clipboard ...

... and paste it (carefully) beneath the Class definition for the MainPage class, but inside
the AroundMe namespace like so:



On like 134, I will rename "RootObject" to:

FlickrData

... it's more descriptive of what its purpose is, and I believe in clear names for variables
and classes. The result should look like this:


Next, I want to actually deserialize the JSON data into instances of these new classes.
To do that, I'll use a third-party but heavily utilized package called Newtonsoft.Json.
I open the Package Manager Console (like I did earlier in this lesson) and type the
following: install-package Newtonsoft.Json

... and hit the enter key.


If all goes well, you should get messages indicating success like you see below:


Now, we need to revisit the UpdateMap() method and modify it to actually perform the
deserialization:


1.  The deserialization is pretty easy ... just one line of code. We call the static DeserializeObject<T> method of the JsonConvert object from Newtonsoft.Json package (not shown here ... you'l  need to add a using statement using the technique I demonstrated earlier). 
2.  The FlickData class has a "stat" property that represents whether the call was successful and contains data. If the "stat" property has the value "ok", we're good to iterate through the data. 
3.  Here we iterate through the the photos.photo property which is a List<Photo>. For each photo ... 
4.  We want to construct a URL that will retrieve each individual photo (line 111). That URL is interesting and gives us an insight into how Flickr stores its data ... photos are saved in different server farms on different servers. Each photo has an ID, and just to protect the service from a hacker trying to hack URLs to find private or hidden data, a property called "secret" is added. Notice that I combine that with the letter "n" indicating the size of the photo I want to retrieve. I'l  have more to say about that later. 
5.  I want to take this newly constructed URL and retrieve that photo from Flickr. To do this, I'l  create a new BitmapImage object passing in the URI for where the photo is located. I'l  give the new BitmapImage to the FlickrImage control's Source property. 
6.  Just for testing purposes, I only need one photo, so I'l  immediately break out of the for each. I'l  revisit this later to grab a bunch of photos and add them for display in a grid. Again, that wil  come later. For now, I just want to make sure I can grab the data and display one photo in my app.

I run the app (F5) to test:


And it seems to work!

Recap
To quickly recap, there were quite a few important takeaways from this lesson ... we
learned about the Flickr API which contains hundreds of method calls giving us access
to practically every feature of Flickr so we can integrate it in our apps. We learned about
getting an API Key and how to call the search API and integrate it into our app. We
learned a little about JSON, how to use the json2.csharp.com website to create class
definitions that match the JSON we want to work with. We learned about the
Newtonsoft.JSON to deserialize the JSON into instances of those classes so we can
work with them in C#, and a lot more.

No comments:

Post a Comment