Connecting to Live with the C++ REST SDK

Connecting to Live with the C++ REST SDK

Rate This
  • Comments 4

Hi, I’m Andy Rich, a QA on the C++ team.  Last week, the C++ team released the C++ REST SDK (codename “Casablanca”) on CodePlex (http://casablanca.codeplex.com).  This blog post will walk you through using the C++ REST SDK to connect your Windows Store apps to Windows Live services.  This example demonstrates how to grab information about the user’s photo albums, but it can be applied to the other Live REST APIs as well.

Prerequisites

In order to connect a Windows Store app to Live Services, you will need:

  • A Windows Store Developer account (sign up here: http://msdn.microsoft.com/en-US/windows).  Note that you will need to provide a credit card to open a developer account. (MSDN subscribers are eligible for a one-time 12-month developer account.)
  • A Visual Studio Project which is associated with a Windows Store app in the Windows Dev Center.  In order to connect to Live, your application will need a real store signing key and package identity, so you must complete the first few steps of the store submission process and associate your project with that app, even if you’re just experimenting with the functionality. I outline the required steps in “Setting up your App,” below.
  • The C++ REST SDK for Visual Studio 2012 (express or full)

Setting up your App

To create a new app in your Dashboard within the Windows Dev Center, click “Submit an app”.  (This will begin the submission process, but your app doesn’t need to be ready for submission just yet!)  You will be asked to reserve a name; this may be changed later, so don’t worry about finding the perfect name for your app right now.

Next, click “Advanced Features” in your app’s dashboard entry and choose “Save.”  You want to ensure that the Advanced Features step shows as “Complete” in your dashboard.

Next, you will need to associate your Visual Studio project with the app entry you made on your developer account.  To do this, right-click your project in Visual Studio, and select Store->Associate an App with the Store.  You will be prompted to log into your developer account, and then shown a list of apps you have started; select the appropriate one, click “next” and then “associate.”

It is vital that you complete this step – without a proper package identity and a store-signed key, Live Services will reject all login requests from your app.

Finally, right-click your project and choose “References,” then click “Add New Reference.”  Select Windows->Extensions and the check the box next to “C++ REST Extension SDK for Windows Store apps” and click “Ok”.  This will add the necessary includes/libs for the C++ REST SDK to your project.  (If you cannot find the necessary reference in the dialog, make sure you have installed the appropriate SDK and try restarting Visual Studio.)

Logging into Live

Let’s work on logging into Live.  This is done by using the Windows Runtime (WinRT) OnlineIdAuthenticator API, which presents users with a consistent and trusted login view across multiple apps.  The user’s consent will be cached with your app, so the login/consent dialog will only appear the first time a user accesses you’re app on a particular computer, unless the login expires or the user logs out.

Include <collection.h> and <ppltasks.h> in your source file and add the following using declarations:

using namespace Platform::Collections;
using namespace Windows::Security::Authentication::OnlineId;
using namespace concurrency;

This code will log the user into Live using the OnlineIdAuthenticator:

       auto auth = ref new OnlineIdAuthenticator();

       auto request = ref new OnlineIdServiceTicketRequest("wl.signin wl.basic wl.photos", "DELEGATION");

       auto request_vec = ref new Vector<OnlineIdServiceTicketRequest^>();

       request_vec->Append(request);

 

       create_task(auth->AuthenticateUserAsync(request_vec, CredentialPromptType::PromptIfNeeded))

       .then([](UserIdentity^ ident){

              auto ticket = ident->Tickets->GetAt(0);

              //token is a global std::wstring
              token = std::wstring(ticket->Value->Data());
       });

We start by creating the OnlineIdAuthenticator object, and then create a request to log into Windows Live.  In this case, we are requesting the wl.signin, wl.basic, and wl.photos scopes.  You can view the full list of Windows Live scopes (and what they permit your app to access) here

The OnlineIdAuthenticator allows you to submit multiple login requests simultaneously, but for our purposes, a single login request is sufficient.  However, to match the AuthenticateUserAsync function’s parameters, we will need to pass our request inside a single-element vector (request_vec).

AuthenticateUserAsync may take over the user’s screen to display the login prompt and gain the user’s consent, so naturally this will be an asynchronous action.  In the code above, we are using a PPL task continuation to inspect the login ticket after the user has consented.  Note that we are not handling error cases where the user has not consented or the authentication fails (for example, due to an incorrect app association).  These cases should be handled using a task-based continuation to catch the error and handle it appropriately.  To learn more about using PPL, I recommend this article.

When the user has logged in and given their consent for your app to access their information, the continuation will be called back.  Interestingly, most of the properties on the UserIdentity that gets returned to you are actually unavailable (unless you are a “Microsoft application partner”).  However, the only property we care about at this point is the security token which is found in the collection of tickets included in the UserIdentity.

The token returned after successful login is required in later steps, and so needs to be stored somewhere for later access.  In the example above, the token is being stored in a global variable; in a full application, this would more appropriately be stored in a member variable and protected against concurrent access and race conditions.

Understanding the Live REST Endpoint

It can be helpful to understand what the Live REST endpoint returns when it is used correctly, and the Live Interactive SDK can be very helpful here.  To use the Interactive SDK, you need to click the small ‘Sign in’ link in the upper right-hand corner of the page and log in using a Windows Live account.  For the following walkthrough, you should use an account which has some pictures stored in the user’s SkyDrive.

After logging in, expand “SkyDrive API” and select “Albums, photos, videos, and tags” and choose “REST” on the right-hand side.  The Request path will be preloaded with “/me/albums,” which will get a list of the logged-in user’s photo albums.  If you click the “Run” button, the Interactive SDK will call to the Live REST API and show the results of the API call in the “Response” section.

The Live REST API returns text formatted as JSON (JavaScript Object Notation). This is a simple web-standard format to return structured data, which many different languages and frameworks have the ability to parse.  Both Windows Runtime (through the Windows::Data::Json namespace) and the C++ REST API (through the web::json namespace) have the ability to parse JSON into object hierarchies which can be inspected and manipulated in code.  We will use the C++ REST API’s JSON parsing in this example.

By viewing the structure of the response in the Interactive SDK, we can understand how the Live REST API returns information about the user’s albums:

{ // top-level object

    "data": [ // array, 1 element per album

    {  //object, 1st element in the array

        "id": "<folder id>",

        "from":

        { //object containing two members:

            "name": "<friendly name of album owner>",

            "id": "<owner’s id>"

        },

        "name": "<album’s friendly name>",

        "description": "<friendly description of album>",

        "parent_id": "<folder id of parent>",

        "size": 405466,

        "comments_count": 0,

        "comments_enabled": true,

        "count": 26,

        "link": "<direct URL to the album>",

        "type": "album",

        "created_time": "2005-08-25T22:37:26+0000",

        "updated_time": "2012-06-06T16:27:37+0000"

    },
    {
/*...*/},{/*...*/}, //... additional albums
  ]
//end of the "data" array
} //end of top-level object

(In the above example, some of the specific field values have been sanitized.) Seeing and understanding the structure of the data can be helpful when we are attempting to parse this information in code.

Accessing the Live REST Endpoint

Now that we have an understanding of the data we will be parsing, we can use the C++ REST SDK to access the Live REST endpoint and pull back information about our user’s albums.

To begin, #include <http_client.h> in your source file. (If this header cannot be found, make sure you have added the C++ REST SDK reference to your project as mentioned in the “Setting up your App” section.)  You’ll also want to add the following using namespace declarations to your source file:

using namespace web;

using namespace web::http;

using namespace web::http::client;

The following source code creates an instance of the http_client class and uses it to access the Live REST API endpoint:

       http_client client(L"https://apis.live.net/v5.0/");

      

       std::wstring request(L"me/albums");

       request.append(L"?access_token="); // live REST API requires the access

       request.append(token);             // token we acquired during login

 

       client.request(methods::GET, request)

       .then([](http_response response) {

              return response.extract_json();

       }).then([](json::value v) {

              //parse v to extract album information

       });

Since the web operation is likely to take some time to return, it is implemented as an asynchronous task.  Once again, we will use PPL continuations to complete the task.  The task returns us the http response, which we know from the Interactive SDK is JSON data.  The C++ REST API includes a helpful extract_json() method which will asynchronously parse the JSON data for us and return it as an object hierarchy that we can then parse in the final continuation.  (You could also call extract_string() at this point to get a std::wstring of the JSON data and pass it to another parser/framework of your choosing.)

If you put a breakpoint in the second continuation, you can use the debugger to inspect the “v” parameter and get a closer look at the data being returned; it should be very similar in structure to the data you saw coming from the Interactive SDK.

Also, as before, this code lacks error handling – for example, the request could fail due to the device losing internet connectivity.  Your program should use task-based continuations to capture and process these error states in a reasonable manner.

Parsing JSON Programmatically with the C++ REST API

The final step is to make sense of or otherwise process the JSON data from the previous step.  Generally, this will involve constructing types relevant to your program that encapsulate the data represented by the returned JSON.  In our case, we will create a map that stores the albums ids, along with their friendly names and the count of photos in those albums.  (You may need to #include <map> in your source file.)

       }).then([](json::value v) {

              std::map<std::wstring, std::tuple<std::wstring, unsigned int>> album_data_map;

 

              for(const auto& it : v[L"data"]) {

                     const auto& album = it.second;

                    

                     album_data_map.emplace(album[L"id"].as_string(),

                           std::make_tuple(album[L"name"].as_string(),

                           album[L"count"].as_integer()));

              }

       });

 

In the C++ REST API, the most important accessor on a json::value is operator[].  This lets you access any named field on the value, which itself will be returned as a json::value type.  We can then use various as_<type>() functions to convert these values into C++ primitive types.

In the example above, we are using a C++11 range-based-for loop to iterate over the elements in the “data” array.  The iteration returns a std::pair, where the first element is a json::value containing the current array index (0-based) and the second element is the json::value of the data at that position in the array.  We then use operator[] to get at various members on the object and store them in our own map for later use by the program.

At various stages, you could introduce error handling or data validation.  It is entirely possible, for example, that a particular album has no friendly name, in which case the as_string() accessor would throw an exception.  You can preemptively test for such conditions by calling check functions such as is_null() and is_string().

You could also parse the JSON data more directly by using the begin and end iterators on json::value.  Each iteration will return you a pair, where the first element will be a json::value containing the name of the field, and the second will be a json::value containing the data for that field.  This blog post shows a code example of parsing JSON data in this manner.

A Note about PPLX and Thread Contexts

The C++ REST API includes an extended version of PPL under the pplx namespace, which is back-ported to older versions of Visual Studio and will be included in the next version of PPL.  The types and functionality of PPLX are nearly the same as standard PPL, but the task and continuation types are distinct from standard PPL.  This means you need to take care to qualify your types when mixing PPL and PPLX; for example, you cannot return a C++ REST API continuation from a function where the return type is specified as concurrency::task<T>; instead you will need to change the return type to pplx::task<T>.  PPLX also provides routines to convert between the two task types (pplx::pplx_task_to_concurrency_task() and pplx::concurrency_task_to_pplx_task()).

Also, unlike with WinRT async operations, continuations in the C++ REST API do not marshal to the calling thread when performing continuations.  This means that attempting to construct, call, or modify UI elements from within a C++ REST API continuation can result in a WrongThreadException.  You can pass an additional parameter to your continuation, task_continuation_context::use_current(), to instruct the continuation to run in the same thread context it was created in.  However, if your continuation performs a lot of processing, it is not ideal to do all of this work on the UI thread, as this can decrease application responsiveness.  In these scenarios, it is best to have the majority of your processing happen in an arbitrary thread context, and then schedule an additional continuation to run on the UI thread:

       // use_current() will only be the UI thread if

       // the current function is called from the UI thread

       auto ui_ctx = pplx::task_continuation_context::use_current();

 

       client.request(methods::GET, request)

       .then([](http_response response) {

              return response.extract_json();

       }).then([](json::value v) {

              //perform expensive processing

              //this will happen off the UI thread

       }).then([](){

              //after processing is complete, update or notify UI changes

       }, ui_ctx); //additional parameter specifies callback context

(Note that in this example, I needed to use pplx::task_continuation_context instead of concurrency::task_continuation_context, because the continuation type of the C++ REST API was a pplx::task and not a concurrency::task.)  For more information on task continuation contexts, consult this documentation.

Final Thoughts

This blog post just scratches the surface of what is possible with the Live REST endpoint.  Browsing the Live Interactive SDK is a great way to understand much of the available functionality (and what data it returns).

Also, note that Windows Store apps that wish to connect to a user’s Live account should adhere to the published guidelines for Store apps.  This includes adding functionality in your app to permit users to log out of their account from within your app using the settings charm.

And finally, the Live SDK is just one of many REST endpoints available to app developers.  Using the techniques employed here, you could add functionality for your app to connect to Facebook, Flickr, Twitter, Reddit, and many other popular online services that provide public REST APIs.  The ways in which you access these APIs will differ depending on the service, but many use OAuth authentication.  The WebAuthenticationBroker API sample can show how to perform OAuth authentication from within a Windows Store application in a trusted way.

  • Absolutely top blog post! I'd like to see a lot more coverage and usage walk thoughts for the C++ REST API. It would be amazing if we could have something equivalent to the the Patterns and Practices book for the C++ Parallal Patterns Library, but for C++ REST. You folks did a great job packaging the the Hilo sample and associcated advice into a pleasant to read PDF, the C++ REST API is unarguably a more import bit of tech than the Hilo sample and deserves at least equal respect and treatment when it comes to being written about. Actually, any chance of some member of the C++ REST team getting together with Microsoft Press and putting out a proper book?

  • Minor point, but is that a mistyping at the end of the posts URL? Surely that should be .../rest.aspx ?

  • I was having some trouble getting the blog to publish yesterday; during that time I created a 'test' post to see if I could work around the issue. When that worked, I replaced the contents of that test post with what you see here; but the URL is a hold-over from my efforts to get the blogging platform to cooperate.  I do have the ability to change it to a more descriptive URL, but now I'm worried that I'll break existing links to the post.

  • Always has.  It's like walking in a dark hallway with glass shards, rusty nails, and cat-throwing old hags.  Time for an enema.  Or bite the bullet: rip it out and put something in the works.  What year is this, anyway.

Page 1 of 1 (4 items)