programming | Help I'm trapped in a code factory!

Making the most of the Google+ developer site


The curse of knowledge – knowing something and then not realizing that you have this knowledge – can make it difficult to remember the first time that you started learning about something. A great example of this is the Google developer documentation. Virtually every set of developer documentation that I have used and contributed to has been unique to the site or project that I have been working on and Google+ is no exception. This is not by design, writers spend hours, weeks, even months planning and mapping out how the documentation will be organized based on how the user will learn from it and how they will find the things that they are looking for. Documentation organization and information architecture are extremely difficult and no particular solution is best.

In this blog post I’ll try and summarize a few key points of how you can use the Google+ developer documentation that I have learned from using it constantly.

A high level overview

In case you have missed it, the Google+ Developer site is at https://developers.google.com/+.

The most important part of being a power user of the Google+ documentation is to understand the navigation bar on the left and what the blocks of content represent. The following diagram summarizes each section:
overview

 

  • At the top, you have the most effective resources for getting started.  These cover the “what is it” and “how do I see it work” topics.  I’ll refer to this as the getting started section.
  • Next, you have a breakdown of Google+ by feature and platform.  I’ll just call this section features and platforms.
  • Next, you have a breakdown of the developer resources that are quick references for the top resources that developers are looking for. I like to think of this as “get the stuff” but really it’s better summarized as Top Resources.
  • Finally, you have the community updates and other broader information for Google+ developers. This is the external/community resource section for Google+.

Given that breakdown, you can jump into each section with some sort of expectations and understanding for what you will encounter. I’ll now dive deeper into each section.

Getting Started

This section covers the first resources that you will want to get to know and experiment with the product. This is breadth content that is not specific to a feature but is generalized to a high level view of the Google+ platform. The key content here is:

  • A quick platform overview for Google+.
  • Getting started samples.  We call these the quickstarts because they should get you going in around 10 minutes. These are broken down by platform / programming language (Android, iOS, Python, etc).
  • The Photohunt sample. This is our showcase demo that brings together the features into something interesting and also demonstrates best practices for end-to-end applications built on Google+.
  • The API reference that lets you understand the full capabilities of the Google+ API platform.

When you dive into this content, you are typically looking to understand the platform overall and quickly get going. When you reach this content, it’s assumed that you want to experiment and explore by diving right into using the platform.

Features and Platforms

This section covers each part of the platform atomically and is the most visually focused content on the developer site. You can look at all of the available features to understand them as well as how to use them. There is a ton of content in this section that is essential to understanding and using the platform. You can also learn about why each feature and platform is useful for you. It’s broken down to cover:

  • Google+ features breakdown by capabilities. Here you can learn all about the core platform features of Google+. Sign-in, interactive posts, app activities, over-the-air installs, and so on.
  • iOS and Android mobile platforms
  • Hangouts

You can think of this section as a palette from which you can paint products. Each of these components is available and summarized for you to understand how it can work for you. Each of the sections contains code and examples ready to copy and paste. When you’re looking for a solution provided by the product / Google+ platform, this is where you go. When you want to see a feature and then jump in to understand how to use it, you can find everything right here. To discover the relevant content you can either dive right in to the platform that you are using, click through the visual content to the highlighted buttons on the top of the page.

Top resources

This section covers much of the “Get it now” contents and resources that can be shared with external folks you are working with.

From this section you can get:

  • The API and SDK resources in the Download section
  • The top best practices content
  • The Branding Guidelines for designing custom UI that conforms to Google+ branding

If you are looking for resources to point agencies to, these are the important ones. If you are looking to get the components for building apps, this is also where you should look.

External / Community for Google+

These links cover the topics for being good citizens in the Google+ ecosystem and getting involved with the exciting things that are going on with Google+. From this section, you will find resources to:

When you are looking to maintain a deep understanding of Google+ and are getting to a more mature state with Google+ development, these sections are essential. You can connect with other people who are developing with Google+, can find resolutions to specific problems, and can learn the intricacies of how we want developers to use Google+.

Thoughts and Conclusions

I know that most people reach our content through search. However, it can be really useful to get acquainted with the layout of our developer content so that you can also explore and discover the relevant content for your Google+ integration. The Google+ content team of writers has put immense amounts of effort into making our site as useful as possible for developers, take advantage of all the work they’ve put in! I’ll add a few more summaries to help you understand a few key things that you should look at and will reference over the course of your career as a Google+ developer.

Requirements for developing with Google+:

API Overviews:

Code:

Please contribute to making the site better through the issue tracker and by telling the Google+ developer team what you think on the Google+ developers page. The feedback that goes through these channels really and truly shapes the future of the platform and the Google+ developer content.

A final note, all of the latest Google+ features are being covered at Google IO this week.  Follow the Google+ track either at the conference, at IO extended meetups, or online to learn all of the great new opportunities that are possible with Google+.

Google API clients: Why you should use them and how


Screen Shot 2013-04-17 at 11.40.18 AM

Some of our older code examples, including many that I have authored on my blog have been using raw query execution against the Google APIs. This is undesirable and is absolutely not a best practice because you will not benefit from the convenience and reliability that comes with using methods on the API.

The beauty of the Google APIs is that they use a discovery service that allows Google and third parties to generate updated packages on the fly for developers to consume in their target languages. What this means is that as the APIs change, the client libraries will automatically be updated to support these changes. Furthermore, these client libraries are owned and tested by Google making them much more stable and reliable than using raw access to the API endpoints.

In this post, I’ll show you first a few bad examples for queries and will show you better ways of accessing Google’s APIs.

The first culprit: client request execution

The Google API clients support performing raw execution against the Google APIs using appropriate network stacks for that particular client.  This is great design because client queries can share the same execution code and benefit from improvements in caching, performance, reliability, and so forth. Additionally, the API will manage authorization and will manage your bearer token for you.  However, accessing the APIs in this manner requires you to parse and manage JSON objects which can introduce bugs and support issues for you, the developer.

For example, in this post, I run the following code (do not do this):

var payload = {
  "target": {
    "id" : "replacewithuniqueidforaddtarget",
    "image" : "http://www.google.com/s2/static/images/GoogleyEyes.png",
    "type" : "http://schema.org/CreativeWork",
    "description" : "The description for the activity",
    "name":"An example of AddActivity"
  },
  "type":"http://schemas.google.com/AddActivity",
  "startDate": "2012-10-31T23:59:59.999Z"
};
var args = {
  'path': '/plus/v1/people/me/moments/vault',
  'method': 'POST',
  'body': JSON.stringify(payload),
  'callback': function(response) {
     console.log(response);
   }
};

gapi.client.request(args);

What this code is doing is directly POSTing JSON data to the API endpoint. This is undesirable because there are a number of ways that things can go wrong and you must write loads of unnecessary and difficult to read code. In addition, you have to stringify the API call when you make it and also parse the response from the query.

Next culprit: XHR / RAW HTTP requests

This is actually worse than the first culprit: rolling your own client using the XHR object in JavaScript. The following example, from code I wrote roughly a year ago, illustrates what not to do (DO NOT DO THIS):

    // globals used for auth, showing debugging
    var debug = true;
    var key   = "AIzaSyC63QTL6Brw_4IQFK6uKRQDj-KmGPKMwnA";

    function handleRequestIssue(request){
        // For now, just can cry about it..
        console.log("khhhhaaaaann!!!, status:" + request.status + " /  response:" + request.responseText);
    }

    // Gets the activities for a profile
    function getActivities(profileID){
      var activities = null;      
      var URL        = "https://www.googleapis.com/plus/v1/people/" + profileID + "/activities/public?alt=json&key=" + key;
      var request = new XMLHttpRequest();
      request.open('GET', URL, false);
      request.send(); // because of "false" above, will block until the request is done 
                      // and status is available. Not recommended, however it works for simple cases.

      if (request.status === 200) {
        if (debug) console.log("retrieved activities nn");
        if (debug) console.log("rawnn" + request.responseText);
        activities = jQuery.parseJSON(request.responseText).items;
        console.log("Discovered " + activities.length + " activities");
        console.log("raw:" + request.responseText);
      }else{
        handleRequestIssue(request);
      }

      return activities;
    }

    function getCommentsForActivity(activityID){
      var comments = "";      
      var URL        = "https://www.googleapis.com/plus/v1/activities/" + activityID + "/comments?alt=json&key=" + key;
      var request = new XMLHttpRequest();
      request.open('GET', URL, false);
      request.send(); // because of "false" above, will block until the request is done 
                      // and status is available. Not recommended, however it works for simple cases.

      if (request.status === 200) {
        if (debug) console.log(request.responseText);
        comments  = jQuery.parseJSON(request.responseText).items;

        if (debug){
          for (comment in comments){
            console.log(comment);
          }
        } 

      }else{
        handleRequestIssue(request);
      }

      return comments;
    }

    function manualTrigger(){
      var activities = getActivities("109716647623830091721");
    }

As you can see, this code is even less readable than the first set of code! I’m even adding an ugly and blatantly terrible error handler that lacks remediation for the response issues. The code is super fragile: changes at multiple points in the process will introduce bugs in my demo. Do not access the APIs this way.

Doing it RIGHT: The Google API Clients

Here is the best way to do this: using the Google API clients and accessing the functionality and data through the API client.  The following JavaScript example lists comments from the current user’s stream and can be seen here: Demo: listing comments (DO IT THIS WAY):

<html>
<script>
    var output;

    function signinCallback(result){
        console.log(result);
        if (result.access_token != null){
          // success
          document.getElementById('signinButton').style.display = 'none';
          output = document.getElementById('output');
        }
        // Load the client library and call getActivities once it's loaded
        gapi.client.load('plus', 'v1', getActivities);
    }

    // Gets the activities for a profile using the client library
    function getActivities(){
      var activities = null;
      gapi.client.plus.activities.list({'userId' : 'me'}).execute(
          function(activities){
            console.log(activities);
            for (var index = 0; index < activities.items.length; index++){
              output.value += 'nn-------n' + JSON.stringify(activities.items[index]);
              output.innerText = output.innerText + JSON.stringify;
              getCommentsForActivity(activities.items[index].id);
            }
          });
    }

    function getCommentsForActivity(activityID){
        gapi.client.plus.comments.list(
            {'activityId' : activityID}).
            execute(
                function(comment){
                  output.value += 'n' + JSON.stringify(comment);
                  console.log(comment);
                });
    }
</script>
<body>

  <span id="signinButton">
    <span
      class="g-signin"
      data-callback="signinCallback"
      data-clientid="1065047579848.apps.googleusercontent.com"
      data-cookiepolicy="single_host_origin"
      data-scope="https://www.googleapis.com/auth/plus.login">
    </span>
  </span>
  <textarea cols="80" rows="40" id="output">
  </textarea>
  <!-- Place this asynchronous JavaScript just before your </body> tag -->
  <script type="text/javascript">
    (function() {
     var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
     po.src = 'https://apis.google.com/js/client:plusone.js';
     var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
   })();
  </script>
</body>
</html>

See how much better it is!  This code is even doing MORE than the other code in fewer lines.  You get nice objects and methods for all of the operations performed on Google+ and the code will be updated from Google if anything ever changes. By accessing the API in this manner, you will be getting all of the client library updates by loading the client library from Google and will get a reliable means of accessing the API functionality.

The Google+ quickstarts show how to use the client libraries in a number of languages, this is a great way to get started with understanding the relevant patterns for your language of choice. Also, this is a great way to learn how to perform the operations in a language you understand less because the samples are virtually identical in all languages.

Conclusion

Although it may seem obvious now, always make sure that you use the Google API clients when programming against the Google APIs. There is a client for virtually every language out there to make your code more maintainable, stable, performant, and readable. The API clients support much more than I covered here that makes your life easier. Many other great examples of client execution can be found on Ian Barber’s blog.  For example, the following article shows how to use the API client to batch API calls:

The generic Google client libraries that use the discovery service can be found at:

You can also download the Google+ API clients from the Google+ developer pages that are targeted to Google+.

For certain languages such as C# and Java, the client libraries must be generated, so occasionally it may be a good idea to update your clients if you’re using these languages. Have fun accessing the APIs, and be sure to do it the right way, using the freely available clients!

Developing in C# from OS X using MonoDevelop


Screen Shot 2013-04-11 at 8.06.44 AM

Before we begin, you can get MonoDevelop from here: MonoDevelop

I have been playing a little bit with MonoDevelop as an alternative to running a VM from OS X for C# development. After spending a little time with it, MonoDevelop really isn’t that bad…

(I can hear the *hissing* from naysayers)

… Really!  It’s not Visual Studio, mind you, but it’s still a great IDE.  For OS X, the latest versions have pretty awesome coverage of the .NET 4.0 specification and C# 4. Even a good portion of the .NET 4.5 specification is supported and C# 5 is on the way!

I’ll go over a few things that I really like and don’t like about the experience so far.

The Good

Code completion is extremely boss in MonoDevelop.  Here you can see the type-ahead completion and extracted documentation rendering in the IDE while I code:

Screen Shot 2013-04-10 at 4.54.11 PM

I love this type of code completion.  Even the most tepid command-line programmers can’t poo-poo this kind of functionality.

 

The Solution View – navigating your files

Next, the IDE does this wonderful thing where only one project is open at a time and provides a clear “solution” view as well as other useful perspectives for viewing, editing, and debugging projects.

Screen Shot 2013-04-10 at 5.16.19 PM

Just like Visual Studio, you can see all of the projects and resources associated with your solution and can easily manage them. Projects unrelated to what you are doing are not cluttering your workspace and sucking up valuable space in your IDE.

Debugging

Here you can see code with a breakpoint and interactive debugging being performed from MonoDevelop, it’s very slick!

Screen Shot 2013-04-10 at 5.23.08 PM

Here you can see the watch and immediate windows, you might exclaim, “I can’t believe it’s not Visual Studio! Same great taste!”

Screen Shot 2013-04-10 at 5.27.20 PM

Overall, the MonoDevelop team has the basics covered and much more, even approaching into addressing all the “nice to have” things as well.

The Bad

Some core library and developer functionality just plain isn’t there.  I’m not sure if it’s Mono, MonoDevelop, OS X, or gremlins, but there are certain times that you will see things like this:

Screen Shot 2013-04-10 at 5.31.15 PM

 

Most of the time, this doesn’t affect you, the coverage that you get on the Mono platform is surprisingly good.

The Ugly

If you are trying to run newer versions of MonoDevelop on a Ubuntu distribution, you’re gonna have a bad time. The latest official version of Mono that ships in Ubuntu is 2.08 and I don’t know how long it will be until official support will be available for newer versions – I’m looking at you versions 2.11+, which include native support for Entity Framework.

Regardless of your Mono version, you will sometimes have to do weird things to get your code working. This could be due to programmer laziness because Visual Studio is basically cruise control + autopilot for programmers or it could be due to the very heterogeneous environments in which Mono(Develop) runs in. Regardless of the cause, you have to do some magic bone waving in order to get your project running if you created it on Windows with Visual Studio.

Using MonoDevelop in practice

Speaking of magic bone waving, I got the Google+ C#/.NET Quickstart working from MonoDevelop on OS X! I only had to do one little trick to get DotNetOpenAuth to stop complaining… the following steps should be enough to get you going:

Follow the same instructions as the quickstart except:

When you run the sample, the server will not by default go to the http://localhost:4567/signin.aspx page. Instead, it will load on the default development port, 8080, and will navigate to index.html the template file used for the project. The easiest way to get around these two things:

  • Add http://localhost:8080 to your project in the Google APIs console
  • Manually enter the URL http://localhost:8080 into your browser when the code runs

That’s it!

Feel free to let me know what you think of MonoDevelop and whether you have any tips for using it, my first foray into using it has shown this to be a very promising, intuitive, and clean IDE. If only I could develop and manage Java projects with such a nice UI and the wonderful code completion and documentation integration…

Targeting Interactive Post recipients in Android


In the April 9th, 2013 Google+ Developers Live, Chirag and I demonstrated how to set the recipients for an Interactive Post in Android.  You can watch the video below:

 

Code from the show

I have added a gist to GitHub for the code showing how I targeted Android interactive shares by combining the listPeopleActivity into the ShareActivity. The following snippets cover the relevant code changes relative to the Android quickstart sample:

Adding the PlusClient.OnPeopleLoadedListenter interface, for the asynchronous method from loadPeople:

public class ShareActivity extends FragmentActivity implements View.OnClickListener,
        OnSignedInListener,
        PlusClient.OnPeopleLoadedListener
        {

A few variables for holding the PlusClient, used for getting the Interactive Share intent, and the ArrayList of people, populated in the onPeopleLoaded callback.

    // Add lists for holding the people from people.list
    private ArrayList<Person> mBestRecipients;
    private PlusClient mPlusClient;

The onPeopleLoaded asynchronous callback implementation:

    // The onPeopleLoaded method for the callback handling the response when the visible
    // people are listed
    @Override
    public void onPeopleLoaded(ConnectionResult status, PersonBuffer personBuffer,
            String nextPageToken) {
        if (status.getErrorCode() == ConnectionResult.SUCCESS) {
        	mBestRecipients.clear();
            try {
                int count = personBuffer.getCount();
                for (int i = 0; i < count; i++) {
                	Person toAdd = personBuffer.get(i).freeze();
                	mBestRecipients.add(toAdd);
                }
            } finally {
                personBuffer.close();
            }
        } else {
            Log.e(TAG, "Error when listing people: " + status);
        }

        Intent intent = getInteractivePostIntent(mPlusClient);  
        startActivityForResult(intent, REQUEST_CODE_INTERACTIVE_POST);
    }

The code for adding the recipients to the post:

        	
        if (best){
        	// Use the recipients list created from people.list...best
        	builder.setRecipients(mBestRecipients);
        }

Additional Notes, Errata

There were a few topics that we would have liked to cover in the episode but just didn’t have enough time for, ended up getting glossed over, or might have been lost when we had recorded live.

While I was setting up the APIs console, I mentioned putting in a meaningful name for the project name.  What I should have indicated was to use an appropriate brand name for your company and an appropriate name for this particular client ID.  When you are setting up the project, you want to make sure to get this right because it can be difficult to change it later on.

I really would have liked to show adding specific users by name.  For example, I was missing Chirag from my list of “BEST” people to share with.  If in code, I wanted to make sure that Chirag was always added as a recipient, I would add him by id using the createPerson method from the platform:

        // Create an interactive post builder.
        PlusShare.Builder builder = new PlusShare.Builder(this, plusClient);       

        builder.addCallToAction(LABEL_VIEW_ITEM, callToActionUrl, callToActionDeepLinkId)
        	.setContentUrl(Uri.parse(getString(R.string.plus_example_deep_link_url)))
        	.setContentDeepLinkId(getString(R.string.plus_example_deep_link_id),
                null, null, null)            
            .setText(mEditSendText.getText().toString());     	

        if (best){
        	// Use the recipients list created from people.list...best
<strong>        	mBestRecipients.add(PlusShare.createPerson("118051310819094153327","Chirag Shah"));</strong>
        	builder.setRecipients(mBestRecipients);
        }

In the above code snippet, you can see how I have created the recipient, Chirag Shah in this case, without using the list of people and instead directly adding by ID and display name.  In practice, this is a more common use case and would probably be done using your own database of users.

Speaking of, I also would have liked to have had a longer discussion on who to target posts to.  For example, you could look at the PhotoHunt app that we ship as part of the Google+ platform documentation.  In this sample, we create an internal social graph of users within the app to people they know on Google+ who have installed the app. For that app, we could target interactive posts to the people who the current user has in their Circles on Google+ and who have already installed the app.

Another note on the code I showed on the gist, the best practice for Android would be to pre-load the list of people when the activity loads as opposed to waiting until the user clicks.  That way, the UI doesn’t lag in cases where there is no internet connectivity. Because I wanted to show the before and after code and lazily copied the code from the ListPeopleActivity, I didn’t end up doing this.

notifications

 

 

Screenshot_2013-04-11-11-08-49

A HUGE point that we didn’t cover was how the targeted posts appear across all platforms.  When you specify a specific person, they will get notifications across all of the places that the notifications appear:

  • Search
  • GMail
  • Google+
  • Mobile
  • and so on

As such, these targeted interactive posts are much more effective at reaching the people listed in the post.

Hope you enjoyed the GDL, it was fun to demo! Here’s a snapshot of Chirag and me during the session:

Screen Shot 2013-04-09 at 4.52.11 PM

Google+ code tricks: Upgrading to the new sign-in / upgrading scopes


I have had many folks ask me how they can do the following things:

  • Upgrade from the traditional OAuth flows to the new one-time-code flow
  • Authorize with just plus.login and then add additional (optional but useful) services to the user’s account

These are great scenarios where developers and site owners can benefit from understanding the user experience and options that are available when moving forward with the new sign-in features of Google+. In this post, I’ll share some of my personal thoughts and experience with adding, changing, and upgrading OAuth v2 scopes with the sign-in button. Note These are preliminary thoughts on how this could be done and are not official guidance – please let me know if you have additional suggestions for ways that this could be done better!

Upgrade from OAuth v2 to sign-in

In this scenario, you have a site that works with the existing OAuth v2 flows, most likely a server-side flow. If you’re looking to upgrade to use the sign-in button flow, your existing users will need to reauthorize your application. This is because the the sign-in button implicitly is requesting the plus.login scope for sign-in. Let’s take a look at the experience for how this scenario would work!

A demo of the upgrade flow

First, look at this page:

Simple Server-side Sign-in Demo

If the page is not loading, you can logout here. After you connect your account, you will reach an authorization page such as the following:

Screen Shot 2013-04-02 at 1.15.42 PM

When you reach the site again, signed in to Google, you will be authorized and the page will know your id and can render your profile.

Let’s now assume we want to upgrade the user’s account to use sign-in in order to add users from Google+ to it. In order to do this, the user must login again, this time using the sign-in button as shown in the following demo:

One-time-code Server-side Sign-in Demo

More on why the user must reauthorize later… but the dialog looks as follows

Screen Shot 2013-04-02 at 1.01.20 PM

After authorizing again, the user’s account will then be upgraded to take advantage of the new Google+ Sign-in features.

Let’s now take a look at the steps used to upgrade your backend database to reflect the upgrade.

Updating the user information in the site’s data model

First, recall the simple example where the userinfo.email scope was requested and the user was authorized using the conventional server-side flow. At this point, your site could have a model for the user similar to the following:

before

Let’s assume that the user has created data associated with that flow, so the (…) could represent additional data specific to your site.  Their account ID has been set, because it’s returned with the plus.email scope so the user’s account credentials already exist in this database on the site.

Next, after you have updated your site to have the new sign-in button and the user reauthorizes, you can update the existing data on your site for the user and can add the additional information returned from Google+.  From a back-end perspective, the model could now look something like this:

after

The refresh token and access token, highlighted in red, are updated after the code-exchange happens server-side on the one-time-code flow. This is done because the new credentials have access to the additional scopes.  The VisibleUser table is also populated with all of the users visible to the site so that the social graph can be taken advantage of.

Next, let’s take a look at the programming steps to upgrade your site.

Steps to upgrade the site

Let’s take a closer look at what was done to accomplish this upgrade path. First, the scopes on the API project must be updated to include the Google+ API.  This is done by turning on the Google+ scope from the API console:

console

Next, the site needs to be updated to include the new sign-in button as described on the Google+ developers documentation page, Google+ sign-in. Summarized briefly, the markup code needs to be added to the site:

    <button
        data-scope="https://www.googleapis.com/auth/plus.login"
        data-requestvisibleactions="http://schemas.google.com/AddActivity"
        data-clientId="YOUR_CLIENT_ID"
        data-accesstype="offline"
        data-callback="onSignInCallback"
        data-theme="dark"
        data-cookiepolicy="single_host_origin">
    </button>

…and a sign-in callback will need to be created that POSTs data to the server-side component:

    /**
     * Hides the sign-in button and connects the server-side app after
     * the user successfully signs in.
     *
     * @param {Object} authResult An Object which contains the access token and
     *   other authentication information.
     */
    onSignInCallback: function(authResult) {
      $('#authResult').html('Auth Result:<br/>');
      for (var field in authResult) {
        $('#authResult').append(' ' + field + ': ' + authResult[field] + '<br/>');
      }
      if (authResult['access_token']) {
        // The user is signed in
        this.authResult = authResult;
        // After we load the Google+ API, render the profile data from Google+.
        gapi.client.load('plus','v1',this.renderProfile);
      } else if (authResult['error']) {
        // There was an error, which means the user is not signed in.
        // As an example, you can troubleshoot by writing to the console:
        console.log('There was an error: ' + authResult['error']);
        $('#authResult').append('Logged out');
        $('#authOps').hide('slow');
        $('#gConnect').show();
      }
      console.log('authResult', authResult);
    }

You can learn more about the one-time-code flow by starting with the Google+ PHP Quickstart, but I’ll go a little further here. In cases where the site already has a user, the account can be looked up by their Google ID, which was most likely an index used previously when getting the user credentials from the userinfo.email scope. By matching the ID to the one returned from the plus.login scope, the account has been determined to have been created before and the credentials can be updated for the authorization credentials to the Google authentication servers. Once you have identified the user to upgrade, the persisted refresh token and access token need to be replaced with the new ones.

What is happening behind the scenes is that the OAuth flow in the original site is requesting only the userinfo.email scope.  In the updated site, the sign-in button is implicitly requesting the plus.login scope so the user must be prompted again for permissions.  When the user authorizes again on the new site, the identifier for the user’s Google account stay the same, so the account can again easily be matched up to reflect the updated permissions.

Adding additional scopes to a user’s account

Related to the first example is when you want a user to sign up for a service without needing to grant full permissions to your application and then later needing to add additional, optional, scopes to the associated account. For example, let’s say that you have a service that uses Google+ for login and creating an account but then later you want to add access to a user’s Google Calendar and Google Drive. What you can do is create a configuration page that dynamically sets the scopes on the sign-in button and then renders the button to reauthorize the user as shown before.

Warning: This is a hack that works for now but is not necessarily a best practice, use at your own risk!

Scare text aside… let’s look at how this could work.

  1. The user signs up, you request only the scopes required for signing up / signing in on your site as seen in the original one-time-code sign-in demo.
  2. Later, you bring the user to a configuration page where they select various scopes and then dynamically add these scopes to an authorization request.

The following demo performs some tricks to programmatically add and change the scopes that are requested and then render the sign-in button programmatically:

Demo: Tricks and hacks for Google+ Sign-in authorization scopes

The (definitely not production, there are global variables!) code for dynamically changing the scopes is as follows:

  var calendarScopeVar = '';
  var driveScopeVar= '';

  function toggleCalendar(){
    if (calendarScopeVar == ''){
      calendarScopeVar = ' https://www.googleapis.com/auth/calendar';
    }else{
      calendarScopeVar = '';
    }
    render();
  }

  function toggleDrive(){
    if (driveScopeVar == ''){
      driveScopeVar = ' https://www.googleapis.com/auth/drive';
    }else{
      driveScopeVar = '';
    }
    render();
  }
  </script>

Checkboxes are added that toggle the scopes:

  <input type="checkbox" onClick="toggleCalendar()"></input>Toggle Calendar<br>
  <input type="checkbox" onClick="toggleDrive()"></input>Toggle Drive<br>
  <div id="outer">
  <div id="gConnect">
    <button id="customBtn"></button>
  </div>
  </div>

Every time that the checkboxes are changed, you re-render the sign-in button as shown in the following code.

  function render() {
    $('#gConnect').empty();
    $('#gConnect').html('<button id="customBtn"></button>');
    var scope = 'https://www.googleapis.com/auth/plus.login';
    scope += ' https://www.googleapis.com/auth/userinfo.email';
    scope += calendarScopeVar;
    scope += driveScopeVar;

    gapi.signin.render('customBtn', {
      'callback': 'onSignInCallback',
      'clientid': '{{ CLIENT_ID }}',
      'cookiepolicy': 'single_host_origin',
      'requestvisibleactions': 'http://schemas.google.com/AddActivity',
      'scope':scope
    });
  }

When the user clicks sign-in, the scopes are requested and the user will be re-authorized. The following image shows the dialog that appears when you select all of the optional scopes.

upgrade_flow

Upon completion of the authorization request, you will again exchange the code server-side to get and update your authorization tokens. After the authorization code is exchanged, the credentials returned will be authorized to have the additional scopes for calendar and/or drive. Upon completion of the authorization flow, you should replace your existing credentials with the updated ones that now have the new authorization parameters set. Note be careful that you don’t remove the scopes that you have already requested and need – plus.login and userinfo.email in this example.

Additional resources

So there you have it, upgrading and replacing scopes using the Google+ sign-in button.  This probably has gotten you thinking about how you can do this on your own sites and in your own experiments. The following links should help to get you going and might spark some creativity for you:

 

Random useful stuff


Image by SP8254

Every day I find things that are insanely nice to have or useful.  These things vary from a blog post that saves me hours of abort/retry/fail to really handy utilities and fancy frameworks. It’s worth mentioning a few here.

Installing RVM on OS X

This blog post on installing RVM on OSX is very informative. The solution proposed at the end of the blog post was enough to get the XCode command line tools to install RVM. The issue with installations on OSX seems to be that their (special, one of a kind, non-standard, etc) compiler is quirky so you must trick it into being more compatible. The relevant line from the article is for the install command`:

rvm install <version> --reconfigure --debug -C --enable-pthread --with-gcc=clang

It’s actually probably worth mentioning that RVM is extremely handy.  There’s nothing worse than having to sudo to install gems or try to manage different versions of Ruby on your machine. Ruby introduces tons of breaking changes with each release, so be careful of which version you are running, particularly if you just got a book for what you thought was the latest version.

Getting alt+drag support in Windows

I love various tweaks in the window managers that are available for Linux.  One most notable feature is the ability to hold alt and drag windows.  There’s a Google code project for Alt dragging behavior that lets me work with the fancy pants window dragging behavior of my favorite Linux window mangers.

Sinatra

The first time that I started learning Ruby development, I learned Rails. I should have started with Sinatra. This simple and concise web server is extremely easy to configure and map.  The following is an example implementation of a web server implementing multiple RESTful endpoints and various web paths:

require 'sinatra'

someJson = <<-QQ
  {
    "glossary": {
        "title": "example glossary",
    "GlossDiv": {
            "title": "S",
      "GlossList": {
                "GlossEntry": {
                    "ID": "SGML",
          "SortAs": "SGML",
          "GlossTerm": "Standard Generalized Markup Language",
          "Acronym": "SGML",
          "Abbrev": "ISO 8879:1986",
          "GlossDef": {
                        "para": "A meta-markup language, used to create markup languages such as DocBook.",
            "GlossSeeAlso": ["GML", "XML"]
                    },
          "GlossSee": "markup"
                }
            }
        }
    }
  }
  QQ

get '/' do
  "Look at me now, look at me now"
end

get '/gus' do
  "I'm getting paper"
end

get '/gus.json' do
  content_type :json
  someJson
end

get '/afile' do
  send afile
end

Yeah, that’s a web server. Not until using this library had I felt there was “nothing left to take away” from such frameworks.

Revisiting a few old friends on the Unix/Linux command line

scp – copy files over ssh.  I always forget the colon on the remote server line.  The following is an example of how I move in to a new machine.

scp ~/.bash_profile user@remoteserver:~/
scp ~/.bashrc user@remoteserver:~/
scp ~/.vimrc user@remoteserver:~/

rsync – copy file differences.  This is amazingly handy when you need to copy large amounts of data over your network because when things go wrong, you can easily start off where you left off. Syntax is just like cp:

rsync -r ~/big_folder/ user@remoteserver:~/

ssh -X – tunnel X11 over SSH.  I don’t use graphical programs remotely, but when I do, I tunnel over ssh.  This is rarely useful because remotely running X is slow and miserable, but sometimes you just gotta and it’s nice to know.

ssh -X <remoteserver>

Odds and ends

But wait, there’s more!  A few odds and ends:

That’s all, folks, thanks for reading :)  Please feel free to share if you have any newish favorite things you’ve found out about.

A tale of two RESTful API queries…


At the suggestion of +Will Norris, I updated this demo code for translating URLs to activity IDs to now use a filter.  The following code highlights the differences:

<       + '/activities/public?fields=items%2Fid%2Citems%2Furl&key=' + key 
---
>       + '/activities/public?key=' + key

The only difference is the fields parameter that I had configured using the fields editor from the API explorer.

I didn’t realize how much less data would be used by the API calls but to illustrate the difference I created some screenshots.

An example of the activity feed from API calls without the filter:

An example of the activity feed from API calls with the filter:

Yeah, there’s a lot less data in the second screenshot, like 20x less data. Actually…

2.65 kb with the filter versus:

97.25 kb without the filter.

This is a difference of 36x. That’s crazy!

If you can’t see the images or want to see the differences for yourself,  compare the console output from the unfiltered version of urltoid and the filtered version of urltoid in your browser.

The key thing to look at in the results is the difference between each of the items.  The content after the line > 0 : Object is the relevant difference, in the first example without the filter there are dozens of fields being returned of varying size, in the second example, only two fields that are relatively small are returned. I have clearly been wasting lots of bandwidth by not filtering my API calls.

After seeing the differences, I will definitely start thinking about filtering specific fields from API calls, it’s easy to do and actually makes the API call output easier to debug. In the grander scheme of things, filtering will save end user’s CPU cycles and bandwidth. If you really wanted to stretch this idea out completely, this means that less power would be used globally, less heat generated by computers, and less fossil fuels consumed for power…  wait, this could reduce global warming!

OK, I got a little carried away there… the moral of the story is this, filter your API calls whenever you can.

Getting an activity ID from a Google+ Post URL


Screenshot of demo application running

Taking the URL to a post and then determining the post ID for additional API calls is a little tricky but also fundamental for the Google+ public data API. First, you have to list activities and then search through them to determine which is the actual activity that you’re searching for. To show you how to take a URL from Google+ and determine the activity ID, I have created a demo application that finds the ID for a post given the URL to the post on Google+. Let’s walk through the demo!

This demo is very minimal, all it does is:

  1. Parse the user ID from the URL.
  2. Search the activities for the given URL.
  3. Match an activity with the same canonical URL link as the post.
  4. Show the activity ID.

The following code parses the user ID from the URL:

  function search(){
    // url is in a text input element with id 'url'
    var url = document.getElementById('url').value;
    searchForUrl(url, 0, '');
  }

  function searchForUrl(searchUrl, queryCount, nextPageToken){
    // https://plus.google.com/{userid}/.../.../
    var userId = searchUrl.split('/')[3];

...

Note that should the URL change, the code too must be updated to reflect the new point for the userid. However, because the API is RESTful, this structure should be pretty stable.

The following code searches for activities:

...

    // Set parameters for the query
    var URL        = 'https://www.googleapis.com/plus/v1/people/' + userId
      + '/activities/public?key=' + key 
      + "&orderBy=recent&pageToken="+nextPageToken;

    performXHR(URL, searchUrl, queryCount, nextPageToken);
  }

  // performXHR - used to trigger the XMLHttpRequest
  function performXHR(URL, postUrl, nextPageToken){
    var request = new XMLHttpRequest();

    request['postUrl'] = postUrl;
    request['nextPageToken'] = nextPageToken;

    request.open('GET', URL, true);
    request.send(); // because of "false" above, will block until the request is done 
                    // and status is available. Not recommended, however it works for simple cases.

    request.onreadystatechange = function(){ 
      if (request.readyState == 4) {
        var query = request['postUrl'];
        var nextPageToken = request['nextpagetoken'];

        var activities = JSON.parse(request.responseText).items;
        nextPageToken = JSON.parse(request.responseText).nextPageToken;

        for (value in activities){
          console.log(value);
        }

        return handleActivities(activities, query, nextPageToken);
      }
    };
  }

This code is a little more complicated. First, the activties/list RESTful API endpoint is formed using the userid from the previous step. Next, the XmlHttpRequest (XHR) is formed and sent.  Finally, the results are parsed into a JSON object.

The following code traverses the activities and tries to match against the url values:

  // handleActivities - Parses and stores activities from the XMLHttpRequest
  function handleActivities(activities, postUrl, queryCount, nextPageToken){
    for (var activity in activities){
      activity = activities[activity];
      if (activity['url'] == postUrl){
        targetActivity = activity;
        document.getElementById('result').value= 'ID is:\n' + activity.id;
        isFound = true;
      }
    }

    if (queryCount < maxQueryCount && !isFound){
      queryCount++;

      // throttle calls using timer to avoid reaching query limit
      setTimeout(searchForUrl(postUrl, queryCount, nextPageToken), 100);
    }  
  }

This code just walks through the returned activities and then checks if any of the activities references the URL being searched for.  If the URL is found, the result is displayed,. IF the URL is not yet found, additional queries are performed, passing the next page token to go deeper into the user’s activities.

The following code is the relevant part from the previous step that shows the id:

      if (activity['url'] == postUrl){
        targetActivity = activity;
        document.getElementById('result').value= 'ID is:\n' + activity.id;
        isFound = true;
      }

Please feel free to ask any questions you have in the comments or on the Google+ link used to +1 / share the post.

Pulling Google+ data into Windows Store apps


If you caught the last GDL show for Google+, I demoed a few things I have been working on, most notably my Google+ demo for Windows 8. The following screenshot shows the app running within the Windows 8 Simulator:

As you can see, it’s a basic Windows Store app and just integrates a simple layout with the GridView control.  I’ll give you a brief overview of how the app works and how you could get started with our APIs in Microsoft’s new app model. This post will be focused on getting the relevant Google+ Data using the REST API.

The sample that was created for this code is available from here:

Please note that this is an early version of the sample, various best practices are not being followed but updates to the sources should address these in the future.

Authentication

A key concept demonstrated in this example is authentication.  Because the most exciting Google+ APIs from the perspective of Windows Store apps require that you be granted permissions by the user, you will probably be most interested in this step. Let’s go over how authentication will work for this app.

Authentication overview

This app is using the installed application flow so the following steps will be performed for authentication and API calls:

  1. Authenticate the user to get a single use access code
  2. Exchange the access code for a refresh token
  3. Use the refresh token to get an access token
  4. Use the access token to perform API calls

Some of the steps are made much easier because of new APIs for Windows Store apps.  However, I had trouble using the .NET client library because some of the referenced classes were deprecated for the new app model. I’ll be looking into what can be done to make the service generator build compatible libraries.

Without further adieu, let’s talk about data, starting with authentication!

Performing Authentication

The following code shows the code for the first OAUTH flow step, prompting the user for their credentials to get an access code:

        public async void Auth()
        {
            Windows.Storage.ApplicationData.Current.LocalSettings.Values["code"] = "";
            if (access_token == null)
            {
                if (refreshToken == null && code == null)
                {
                    try
                    {
                        String GoogleURL = "https://accounts.google.com/o/oauth2/auth?client_id=" + Uri.EscapeDataString(clientID) + "&redirect_uri=" + Uri.EscapeDataString(callbackUrl) + "&response_type=code&scope=" + Uri.EscapeDataString(scope);

                        System.Uri StartUri = new Uri(GoogleURL);
                        // When using the desktop flow, the success code is displayed in the html title of this end uri
                        System.Uri EndUri = new Uri("https://accounts.google.com/o/oauth2/approval?");

                        DebugPrint("Navigating to: " + GoogleURL);

                        WebAuthenticationResult WebAuthenticationResult = await WebAuthenticationBroker.AuthenticateAsync(
                                                                WebAuthenticationOptions.UseTitle,
                                                                StartUri,
                                                                EndUri);
                        if (WebAuthenticationResult.ResponseStatus == WebAuthenticationStatus.Success)
                        {
                            string response = WebAuthenticationResult.ResponseData.ToString();
                            // strip to start of auth code

                            code = response.Substring(response.IndexOf("=") + 1);
                            Windows.Storage.ApplicationData.Current.LocalSettings.Values["code"] = code;
                            // TODO: switch off button, enable writes, etc.
                        }
                        else if (WebAuthenticationResult.ResponseStatus == WebAuthenticationStatus.ErrorHttp)
                        {                            
                            //TODO: handle WebAuthenticationResult.ResponseErrorDetail.ToString()
                        }
                        else
                        {
                            // This could be a response status of 400 / 401
                            // Could be really useful to print debugging information such as "Your applicationID is probably wrong"
                            //TODO: handle WebAuthenticationResult.ResponseStatus.ToString()
                        }
                    }
                    catch (Exception Error)
                    {
                        //
                        // Bad Parameter, SSL/TLS Errors and Network Unavailable errors are to be handled here.
                        //
                        DebugPrint(Error.ToString());
                    }
                }
            }
            codeToAcccesTok();            
        }

What is going on in this code snippet is the WebAuthenticationBroker is used to perform the basic OAUTH flow.  The result of this flow is a “code” value. This code is a single use code that can be exchanged for a refresh token and an access token. Now that we have the code, it’s time to exchange that code for an access token and a refresh token. The following code snippet shows how that’s done using a HTTP Post method and the HttpClient class:

private async void codeToAcccesTok()
        {
            string oauthUrl = "https://accounts.google.com/o/oauth2/token";

            HttpClient theAuthClient = new HttpClient();
            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, oauthUrl); 

            // default case, we have an authentication code, want a refresh/access token            
            string content = "code=" + code + "&" +
                "client_id=" + clientID + "&" +
                "client_secret=" + clientSecret + "&" +
                "redirect_uri=" + callbackUrl + "&" +
                "grant_type=authorization_code";

            if (refreshToken != null)
            {
                content = "refresh_token=" + refreshToken + "&" +
                "client_id=" + clientID + "&" +
                "client_secret=" + clientSecret + "&" +
                "grant_type=refresh_token";
            }

            request.Method = HttpMethod.Post;
            request.Content = new StreamContent(new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(content)));
            request.Content.Headers.Add("Content-Type", "application/x-www-form-urlencoded");

            try
            {                
                HttpResponseMessage response = await theAuthClient.SendAsync(request);
                parseAccessToken(response);
            }
            catch (HttpRequestException hre)
            {

            }            
        }

In the above code snippet,  we setup an HTTP POST request and then send it to the Google authorization server with the parameters we need for authentication. The response data from the call contains a parameter for the access token as well as a refresh token. The following code snippet shows how the access token and refresh token are parsed from the response.

private async void codeToAcccesTok()
        {
            string oauthUrl = "https://accounts.google.com/o/oauth2/token";

            HttpClient theAuthClient = new HttpClient();

            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, oauthUrl); 

            // default case, we have an authentication code, want a refresh/access token            
            string content = "code=" + code + "&" +
                "client_id=" + clientID + "&" +
                "client_secret=" + clientSecret + "&" +
                "redirect_uri=" + callbackUrl + "&" +
                "grant_type=authorization_code";

            if (refreshToken != null)
            {
                content = "refresh_token=" + refreshToken + "&" +
                "client_id=" + clientID + "&" +
                "client_secret=" + clientSecret + "&" +
                "grant_type=refresh_token";
            }

            request.Method = HttpMethod.Post;
            request.Content = new StreamContent(new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(content)));
            request.Content.Headers.Add("Content-Type", "application/x-www-form-urlencoded");

            try
            {                
                HttpResponseMessage response = await theAuthClient.SendAsync(request);
                parseAccessToken(response);
            }
            catch (HttpRequestException hre)
            {

            }            
        }

        public async void parseAccessToken(HttpResponseMessage response)
        {
            string content = await response.Content.ReadAsStringAsync();

            if (content != null)
            {
                string[] lines = content.Replace("\"", "").Replace(" ","").Replace(",","").Split('\n');
                for (int i = 0; i < lines.Length; i++)
                {
                    string[] paramSplit = lines[i].Split(':');
                    if (paramSplit[0].Equals("access_token")){
                        access_token = paramSplit[1];                        
                    }
                    if (paramSplit[0].Equals("refresh_token")){
                        refreshToken = paramSplit[1];
                        Windows.Storage.ApplicationData.Current.LocalSettings.Values["refreshToken"] = refreshToken;
                    }
                }
                if (access_token != null)
                {
                    getProfile();
                }
                else
                {
                    // something is wrong, fix this
                }
            }
        }

In the above code, the parameters are extracted from the response data and parsed with a few simple string split calls. The refresh token is stored for later and the access token is cached for API calls. Because the parameters used for exchanging an access code for an access token/refresh token are very similar to those used when exchanging a refresh token for an access token, this method is reused later to get access tokens from the refresh token.

At this point, you have used the access code to get a refresh token and access token.  Now you’re ready to make authenticated API calls to Google+.

Performing authenticated API calls to Google+

In order to perform authenticated API calls to Google+, you need first to have gotten an access token.  This was done in the previous steps and is cached within the application. Next, you will make the API call using a HttpClient.  Finally, you will be serializing the objects from JSON. The first step we’ll discuss is specifying objects to be used later for JSON serialization.

Specifying objects for JSON serialization

Before you can parse JSON data from API responses, you need to specify the objects that will be parsed from the API call responses returned over REST. You can generate these classes from the discovery document. Because this was just an exploration of Metro and a demo, I hand crafted a few of the classes as opposed to writing a generator. The following example is the ActorClass and it’s child classes, which are returned within the activity feed and the people APIs.

        [System.Runtime.Serialization.DataContractAttribute()]
        public partial class NameClass
        {

            [System.Runtime.Serialization.DataMemberAttribute()]
            public string familyName {get; set;}

            [System.Runtime.Serialization.DataMemberAttribute()]
            public string givenName { get; set; }
        }

        [System.Runtime.Serialization.DataContractAttribute()]
        public partial class ImageClass
        {

            [System.Runtime.Serialization.DataMemberAttribute()]
            public string url { get; set; }
        }

        [System.Runtime.Serialization.DataContractAttribute()]
        public partial class ActorClass
        {

            [System.Runtime.Serialization.DataMemberAttribute()]
            public string id { get; set; }

            [System.Runtime.Serialization.DataMemberAttribute()]
            public string displayName { get; set; }

            [System.Runtime.Serialization.DataMemberAttribute()]
            public string nickname { get; set; }

            [System.Runtime.Serialization.DataMemberAttribute()]
            public string tagline { get; set; }

            [System.Runtime.Serialization.DataMemberAttribute()]
            public NameClass name { get; set; }

            [System.Runtime.Serialization.DataMemberAttribute()]
            public string url { get; set; }

            [System.Runtime.Serialization.DataMemberAttribute()]
            public ImageClass image { get; set; }
        }

The classes and interfaces are specified using a shorthand that is common in C#/.NET for data contracts. Now that we have our objects for serialization, we’re ready to get the profile data and then serialize it to the actual objects.

Getting the user’s profile data

Here’s our favorite authenticated Google+ API call, getting profile data! First, we’ll need to specify the template that will be used by the JSON parser for storing the user’s profile object. This was described briefly in the above section.

Next, we’ll perform the RESTful query using the HttpClient.

        public async void getProfile()
        {
            httpClient = new HttpClient();

            var searchUrl = "https://www.googleapis.com/plus/v1/people/me/";

            httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + access_token);

            try
            {
                HttpResponseMessage response = await httpClient.GetAsync(searchUrl);
                ParseProfile(response);
            }
            catch (HttpRequestException hre)
            {
                DebugPrint(hre.Message);
            }
        }

Finally, parse the profile into the object we specified earlier.

        private async void ParseProfile(HttpResponseMessage response)
        {
            string content = await response.Content.ReadAsStringAsync();

            if (content != null)
            {
                var serializer = new DataContractJsonSerializer(typeof(ActorClass));
                thisUser = serializer.ReadObject(new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(content))) as ActorClass;
                ((MainPage)renderArea).RenderUser();
                GetActivities();
            }            
        }

You’ll now have an object, ActorClass, that has been populated with the information of the currently authenticated user.  If you want to inspect the object, put a breakpoint into the application and see what’s in there.  The following screenshot shows this in my project:

You can see the profile information for me in the object. This can be used later to render personalized data for the signed-in user. In my app’s case, the code behind just sets up the XAML objects based on the Actor object.

Conclusions

It’s really not that hard to run the REST flows from Windows Store apps. I think a logical next step for developers working on Windows 8 with Google+ is to implement a share contract because that would be really useful for users. Let me know if you have any questions about the sample! I’ll try and document the rest of how things work and how the UX works, but no guarantees because this is lower priority for me for now.

Finally, for y’all in the U.S., happy Thanksgiving!  I hope you’re having a great time with your family and friends.

See Also