I am a programmer and architect (the kind that writes code) with a focus on testing and open source; I maintain the PHPUnit_Selenium project. I believe programming is one of the hardest and most beautiful jobs in the world. Giorgio is a DZone MVB and is not an employee of DZone and has posted 635 posts at DZone. You can read more from them at their website. View Full User Profile

Practical Google+ Api

09.20.2011
| 6630 views |
  • submit to reddit

Google+ recently releases to developers the first version of its Api, which focuses on public data about profiles and their activities: status updates, resharings and links.

I dived into the Api and wrote a small sample application to get a feel of how easy is to get started, and what can we do with the Api for now. All the code is at the bottom of this post.

The steps

The process that gets to your first request to the Api is not a 1-click one, but since it is oriented to developers I guess we'll manage to get it to work. By comparison, it's not much harder than the same Facebook process.
You should:

  1. Register an application with your Google account, obtaining the necessary Api key and secret. You're not force to a public web server - you can just use localhost or another local host name; in the latter case, be sure to use something like example.com to get it to validate; point that through /etc/hosts or your DNS to a virtual host on 127.0.0.1.
  2. Download a client library (for Java, Python, Ruby, PHP, Objective-C, .NET) and a sample page from the starter project where applicable. In my case PHP I chose PHP, so I downloaded the library plus the index.php and style.css from the starter application; you don't need to follow the setup of the library if you already have index.php from the starter application, which contains everything you need.
  3. Configure index.php with your application credentials, Api key and so on. You can then hack around with var_dump(). For other languages, you may have to instance the classes from the library yourself.

Note that in the initial configuration will make you use https by default, but it's an overkill for a simple test with localhost if you do not have already an Apache instance set up with a certificate. You can use http:// in place of https:// everywhere.

How it works?

The Api covers profile information (People) and public updates (Activities). However, you have to setup OAuth 2.0 for accessing the current user's information. This method of authorization is already used by Facebook and Twitter and it is becoming a standard, allowing the user to avoid sharing his social network's password or sensitive account information with every application.

The process works as follows:

  1. The Api client generates a link on a trusted page on plus.google.com that the user has to follow.
  2. The user follows and authorize usage of his data on that link.
  3. He is redirected back to an Url you have previously specified, either with an error code or with an access token you can use to make requests.
  4. Once you have the access token, you can make requests to the Api; since it is an user-specific information, it can be saved in the session. Once saved, a further redirect is made to a clean Url of your application.

Logout simply consists in deleting the token. The token can theoretically be revoked without the application's intervention, but I cannot find an authorization manager on Google+ yet.

Currently the Api has a limit of 1,000 requests a day.

PHP-specific information

The PHP Api provides associative, multilevel arrays as the retrieved data. For example, this is my profile:

array(9) {
  ["kind"]=>
    string(11) "plus#person"
  ["id"]=>
    string(21) "111746708330132898280"
  ["displayName"]=>
    string(14) "Giorgio Sironi"
    ...

While Activities are organized into some global fields and an *items* key which contains the list:

array(8) {
  ["kind"]=>
  string(17) "plus#activityFeed"
  ["selfLink"]=>
  string(82) "https://www.googleapis.com/plus/v1/people/111746708330132898280/activities/public?"
  ["title"]=>
  string(44) "Plus Public Activity Feed for Giorgio Sironi"
  ["updated"]=>
  string(24) "2011-09-19T22:48:56.907Z"
  ["items"]=>
  array(100) {
    [32]=>
    array(12) {
      ["kind"]=>
      string(13) "plus#activity"
      ["title"]=>
      string(100) "Reshared post from Tim O'Reilly   This New York Times piece on the Amazon-California sales tax d..."
      ["published"]=>
      string(24) "2011-09-05T19:14:06.508Z"
      ["url"]=>
      string(63) "https://plus.google.com/111746708330132898280/posts/LzpB6wNJpoZ"
      ["object"]=>
      array(9) {
        ["content"]=>
        string(4031) "This New York Times piece on the Amazon-California sales tax dispute misses the long-term perspective..."
        ...
      }
      ...

I omitted many fields from this dump for brevity's sake.

Of course you can and should wrap the Api in an Adapter, in order to hide the procedural structured and pass back data organized as objects.

My example

This code largely consists of the OAuth machinery featured by the PHP starter application. It originally provided a list of all my activities: everything I have published on my wall as Public.

 

 

 

 

 

 

 

 

 

 

I added some manipulation: an ordering by descending length of the ['object']['content'] field. Note that reshared posts have the same content field as the original, so some of Tim O'Reilly's posts came out on top.

I deleted my Api keys, but this script has not been altered in any other way from the screenshots you see.

<?php
require_once 'google-api-php-client/src/apiClient.php';
require_once 'google-api-php-client/src/contrib/apiPlusService.php';

session_start();

$client = new apiClient();
$client->setApplicationName("Google+ PHP Starter Application");
// Visit https://code.google.com/apis/console to generate your
// oauth2_client_id, oauth2_client_secret, and to register your oauth2_redirect_uri.
$client->setClientId('...');
$client->setClientSecret('...');
$client->setRedirectUri('http://googleplussample.com/index.php');
$client->setDeveloperKey('...');
$client->setScopes(array('https://www.googleapis.com/auth/plus.me'));
$plus = new apiPlusService($client);

if (isset($_REQUEST['logout'])) {
  unset($_SESSION['access_token']);
}

if (isset($_GET['code'])) {
  $client->authenticate();
  $_SESSION['access_token'] = $client->getAccessToken();
  header('Location: http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']);
}

if (isset($_SESSION['access_token'])) {
  $client->setAccessToken($_SESSION['access_token']);
}

if ($client->getAccessToken()) {
  $me = $plus->people->get('me');

  $optParams = array('maxResults' => 100);
  $activities = $plus->activities->listActivities('me', 'public', $optParams);
  $items = $activities['items'];
  uasort($items, function($first, $second) {
    if (strlen($first['object']['content']) > strlen($second['object']['content'])) {
        return -1;
    }
    if (strlen($first['object']['content']) < strlen($second['object']['content'])) {
        return 1;
    }
    return 0;
  });
  $activities['items'] = $items;

  // The access token may have been updated lazily.
  $_SESSION['access_token'] = $client->getAccessToken();
} else {
  $authUrl = $client->createAuthUrl();
}
?>
<!doctype html>
<html>
<head><link rel='stylesheet' href="style.css" /></head>
<body>
<header><h1>Google+ Sample App</h1></header>
<div class="box">
 
<?php if(isset($me) && isset($activities)): ?>
<div class="me">
  <a rel="me" href="<?php echo $me['url'] ?>"><?php print $me['displayName'] ?></a>
  <div><img src="<?php echo $me['image']['url'];?>?sz=82" /></div>
</div>

<div class="activities">Your Activities:
  <?php foreach($activities['items'] as $activity): ?>
    <div class="activity">
      <a href="<?php print $activity['url'] ?>"><?php print $activity['title'] ?></a>
      <?php print $activity['object']['content'] ?>
    </div>
  <?php endforeach ?>
</div>
<?php endif ?>
<?php
  if(isset($authUrl)) {
    print "<a class='login' href="$authUrl">Connect Me!</a>";
  } else {
    print "<a class='logout' href="?logout">Logout</a>";
  }
?>
</div>
</body>
</html>
Published at DZone with permission of Giorgio Sironi, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)