Part 26: Retrieving a Photo from Flickr's API

Play Part 26: Retrieving a Photo from Flickr's API
Sign in to queue

Description

Source Code: https://aka.ms/absbeginnerdevwp8
PDF Version: https://aka.ms/absbeginnerdevwp8pdf

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'll do a little investigation into the Flickr API to see how we can leverage it in our app
  2. We'll get setup with Flickr so that we can make calls to their API, and get examples of how to call the method we want to utilize
  3. We'll 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'll figure out how to parse through it and actually 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

Navigate to: http://www.flickr.com/services/api/

This is the home page for Flickr's API.

Generic Episode Image

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.

Generic Episode Image

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.

Generic Episode Image

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.

Generic Episode Image

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":

Generic Episode Image

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:

Generic Episode Image

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.

Generic Episode Image

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

Generic Episode Image

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.

Generic Episode Image

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.

Generic Episode Image

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.

Generic Episode Image

 

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":

 

Generic Episode Image

 

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.

 

Generic Episode Image

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.

Generic Episode Image

 

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.

 

Generic Episode Image

 

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

My next changes will be in the ContentPanel.

 

Generic Episode Image

 

  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.

 

Generic Episode Image

 

  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

 

Generic Episode Image

 

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:

 

Generic Episode Image

  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

Generic Episode Image

 

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

 

Generic Episode Image

 

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

 

Generic Episode Image

 

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.

Generic Episode Image

 

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.

 

Generic Episode Image

 

  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 a URL 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 will be decoded and understood the way we want them to be understood. It's a form of packing and unpacking a suitcase that you'll 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'll use for the web api call.
  5. Here we actually make the call to Flickr by passing our newly constructed URL to the HttpClient's GetStringAsync() method. When it returns, we'll display it in the TextBlock I added earlier. I do this so I can actually see what we're getting back from the web service.

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

 

Generic Episode Image

 

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 deserialize it 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:

 

Generic Episode Image

 

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:

 

Generic Episode Image

 

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

 

Generic Episode Image

 

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

http://json2csharp.com

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

 

Generic Episode Image

 

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

I click the "Copy" button ...

 

Generic Episode Image

 

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

 

Generic Episode Image

 

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

 

Generic Episode Image

 

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:

 

Generic Episode Image

 

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.

 

Generic Episode Image

 

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

 

Generic Episode Image

 

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

 

Generic Episode Image

 

  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'll 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'll 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'll create a new BitmapImage object passing in the URI for where the photo is located. I'll give the new BitmapImage to the FlickrImage control's Source property.
  6. Just for testing purposes, I only need one photo, so I'll immediately break out of the for each. I'll revisit this later to grab a bunch of photos and add them for display in a grid. Again, that will 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:

 

Generic Episode Image

 

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.

Embed

Download

The Discussion

  • User profile image
    manpreet

    hi,
    I want to develop an application which uploads users photographs to a remote server. for eg there is a photo called pic.jpg. now I want to upload this to www.abc.com/images folder. how can I do that??

  • User profile image
    rcroeder

    the url for the json2.csharp should not have the period

    RC

  • User profile image
    BobTabor

    @manpreet: You have a few options, but that is a large topic, to large for me to cover here.  Either Angel build FTP into your app, or (b) see what you can accomplish with WCF, or ( c ) perhaps you can use an Azure service + API like this article discusses:

    http://www.windowsazure.com/en-us/develop/mobile/tutorials/upload-images-to-storage-dotnet/

  • User profile image
    BobTabor

    @rcroeder: Thank you, fixed it in the TEXT version (above).

  • User profile image
    wsantosf

    The image below the following text is wrong:

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

  • User profile image
    kushal bhatia

    hii,
    i want to built an app which can access my geolocation and give me near by ATM machine address and also direction for that ??
    how can i do that ???

  • User profile image
    BobTabor

    @wsantosf: Thanks, I'll look into that.

    @kushal bhatia: Yikes ... I suppose that's possible, but I have no idea how to go about it.  Sorry!  Sad

  • User profile image
    RandomAlec

    Ok, I'm having an issue that is really driving me crazy and I can't figure it out.

    I followed the video and text of this lesson many times over up to the part where we run the emulator at 25 minutes, but my emulator cuts out right before it displays the data I need.

    When it cuts out it then points to my

    string flickrResult = await client.GetStringAsync(baseUrl);

    and then states that the HttpRequestException was unhandled by user code.

  • User profile image
    Clint

    @RandomAlec: use a breakpoint at that line, hover over baseUrl and verify that Url works in an actual web browser and you are returning data.

  • User profile image
    Clint

    @RandomAlec: betting it may be the flickr API key, verify you are using your own personal one.

  • User profile image
    fatal1ty

    I have the same problem as RandomAlec. I have verified that the baseUrl works and that I put my own API Key.

  • User profile image
    RandomAlec

    @Clint: My API key is definitely correct, I checked many times over before posting my comment. I will try the Url in an actual web browser to check it.

     

  • User profile image
    Clint

    @fatal1ty: @RandomAlec: are you guys including lat / long?  Bob did make a mistake that he points out in the end of part 27 that I caught after the videos were made.

    Lat / Long must be rounded to 5 or less decimal points for Flickr's API to work.  Bob used the emulator with a location set which rounds to 4 so he never ran into this.

    If this doesn't solve your issue, zip up your solution and file a bug at https://absolutebeginner.codeplex.com/workitem/list/basic and I'll take a quick look to see what is happening.

  • User profile image
    Jurgen

    Hi Bob and all others,
    I am new to C# and phone developing, using german visual studio.

    In the german version of visual studio, I had the problem, that decimal numbers are returned with a comma, insteed of a point.
    (Like 41,12334 not 41.12334)
    The flickr api always returns invalid value for lat/long.

    So I looked around in the internet and found a way which worked
    for me.


    I did it like this, the rounding I included too :

    string str_lat = Math.Round(gpsCoorCenter.Latitude,5).ToString(CultureInfo.InvariantCulture.NumberFormat);

    string str_long = Math.Round(gpsCoorCenter.Longitude,5).ToString(CultureInfo.InvariantCulture.NumberFormat);

    After I passed this results to the url.

    Cheers
    Jurgen


  • User profile image
    BobTabor

    @Jurgen: Thank you, awesome tip!

  • User profile image
    Denis

    Hi!
    Flickr request returns an empty result when uri doesn't contain a text argument. I pass an empty value (text='') then it works.
    Thanks!

  • User profile image
    Abdallah

    Thanks Mr.Bob for this awesome tutorial .

    it works when i put "&text=a" on the url or any letter ..

  • User profile image
    Tomek

    @Bob thank you for great tutorial!<br>Does anyone get same error as me during package installation ?Install failed. Rolling back...
    Install-Package : Failed to add reference to 'System.IO'.
    At line:1 char:1
    + Install-Package Microsoft.Net.Http
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [Install-Package], InvalidOperationException
    + FullyQualifiedErrorId : NuGetCmdletUnhandledException,NuGet.PowerShell.Commands.InstallPackageCommand

  • User profile image
    Clint

    @Tomek: My gut says you need to update Nuget.  This post has the steps to do it.  https://channel9.msdn.com/Series/Windows-Phone-8-Development-for-Absolute-Beginners/Part-17-Introducing-the-Coding4Fun-Toolkit

    1. Go to the Tools Menu –> Extensions and Updates
    2. Go to the Update Tab –> Visual Studio Gallery

      nugetUpdate
    3. Click Update
    4. Restart Visual Studio
  • User profile image
    Heena Buddhadev

    hi,
    I want to develop an application which uploads users photographs to a Flickr.com.

  • User profile image
    Clint

    @Heena Buddhadev: awesome!  check out http://www.flickr.com/services/api/ for how to use their APIs.

  • User profile image
    Tomek

    @Clint, Thank you it helped!

  • User profile image
    devlife3
  • User profile image
    Clint
    @devlife3: dude, that is awesome! Nice find
  • User profile image
    Sheshu

    Hi Bob,

    i am playing with the json web services and i got an issue with https certificate. My server lets say, something.net is using something.com's certificate and i have to ignore and retrieve the data. Is there any way to do that in windows phone 8?

  • User profile image
    Clint

    @Sheshu: we're supporting only the lessons here, for that question, head over to the forums on https://dev.windowsphone.com or www.stackoverflow.com

  • User profile image
    sanjay

    Hi,

    I am getting below exception.
    "A first chance exception of type 'System.IO.FileNotFoundException' occurred in mscorlib.ni.dll

    If there is a handler for this exception, the program may be safely continued."

    if ,my key seems to be alright. if I use the URl to the explorer then it seems to work:" asking me to save or open rest.json...?" .

    I also used the method UpdateMap() as it is from the sample solution and changed my key. I see the same issue.
    any clue here please?

    Sanjay

  • User profile image
    Sanjay

    adding additional information:

    the above exception happens during the execution of the line:
    string flickrResult = await client.GetStringAsync(baseUrl);

  • User profile image
    Vyshali

    Thanks Bob, Clint and Larry for this amazing video series :) I hope I'm not asking a silly question.. but how did you come up with URL construction? Thanks!

  • User profile image
    Clint
    @sanjay: something else is happening. I would set a break point near when you try to open up / write to a file.
  • User profile image
    Clint
    @Vyshali: I looked at Flickr API documents which we link to. Since it is a RESTful API, it is very easy to build out the URL like we did.
  • User profile image
    sanjay

    HI Client,

    Thanks for saying some this else is happening.
    really the internet connection in the emulator was missing. I shifted to new place for winter vacation but I didn't set up the internet connection.

    Now it works.

    Sanjay

  • User profile image
    MongolZ

    Hi Clint,
    I get 404 Exception when tried to connect to flickr (the same as for example RandomAlec). However, I went mad and restarted my PC, and after that it worked. Any clue what happened? I did not change anything.

    Another issue, the Replace(",","%2C") method is not working, my license string contains the same commas, so I had to hard-code them. Don't know really why.

  • User profile image
    MongolZ

    Shame on me, the Replace method works well. Forget that.

  • User profile image
    Jas

    Sir,
    I have almost tried everything. But Flickr Image is not displaying in image box. Please help me.

  • User profile image
    Jas

    Problem Solved. I was using flicker instead of flickr in photoUrl

  • User profile image
    ahmed shabaan

    hi,
    your code run first time and when run it again throw exception

  • User profile image
    ahmed

    I'm watched last part of video and problem not solved and I have the same Bug :'(

  • User profile image
    Stephan

    Excellent tutorials, I guess you could also use the JSON output of Flickr to generate the class with Json2csharp. But my main question is why don't you use sperate folders. I.e. A folder for the classes (like the FlickrData-class) or even better a sperate project for the Flickr classes and methods, so you can use it in some other projects later. Or is this out of scope? Just wondering.

  • User profile image
    mheffels

    @BobTabor:I had the same issue as @Jurgen, but fixed it a by hardcoding the CultureInfo in formatting of the base URL, like so:

     var baseUrl = string.Format(new CultureInfo("en-US"), url, etcetc

     

  • User profile image
    Patrick

    @BobTabor: These tutorials are awesome. I know its a year later, but I'm really struggling. I have a JSON string with lists inside lists inside lists. and I'm unable to dig down through these layers with your method of deserialization. I can only get to the second layer. I tried using dictionaries and expandoObject (which seems to give the right structure) but I can't get at the data. Is there an easy way to dig maybe 4 arrays down?

  • User profile image
    Patrick

    I was not stipulating which branch to go down and so it was confused.

    System.Diagnostics.Debug.WriteLine(apiData.jobsByDateList[0].jobsList[0].interestLevel);


    I was trying to get in using

    System.Diagnostics.Debug.WriteLine(apiData.jobsByDateList.jobsList.interestLevel);

    like your example and intellisense was freaking out.

    With the [0] I'm now able to drill in just fine and don't need the expandoobject. Just needed to sleep on it. :-)

  • User profile image
    nguyen

    Hi Bob,

    I want to search some animated gif images from Flickr. Because uploaded images had been resized and converted, they cannot animate. Only orignial size images can animate. But I don't know how to get the original size images in the json result. How can I do this?

    Thanks

  • User profile image
    milincjoshi

    hi Bob,

    I am facing an issue regarding an exception 404. I followed alll of your instructions but when i run the app it throws following Exception :-

    "An exception of type 'System.Net.Http.HttpRequestException' occurred in mscorlib.ni.dll but was not handled in user code

    Additional information: Response status code does not indicate success: 404 ()."

    i am stuck here for nearly a week. Kindly help me with this error

  • User profile image
    Archana

    Image is not getting displayed. I 've put a breakpoint on setting imagesource line and checked the uri in webbrowser. It displayed the image. But in app its not getting displayed

  • User profile image
    Ramakrishna Ganesh

    Could anyone please help me to show a POINTER(Push Pin) at the location on a map using map control/maps task ?

Add Your 2 Cents