360-320-6221 caperren@caperren.com

Part 2 – Getting the Barebones Google Example Working

Prev    Next

Okay, now we finally get to make something happen with the Drive API! At the bottom of the page is the full source code for Google’s Drive javascript example, and here I’ll be breaking it apart and explaining how it works. You’ll also notice after reading it that the javascript is currently an inline script in an html file. In the next section, I’ll separate this into individual html and javascript files, and add features to begin showing off the real power of the Drive API. For now though, let’s start with their intro.

Rather than look at this code sequentially by the content in the document, I’ll pull it apart in the order that things actually happen when the document is loaded in a browser.

Starting from the html side, which I won’t bother showing code blocks for, there is a div to hold a button for authorizing the API if a user is not authenticated yet, and a pre-formatted output placeholder. The rest of the document is an include for the Google API javascript client library and the inline javascript.

Initial Auth Check

<script src="https://apis.google.com/js/client.js?onload=checkAuth">

So, the the first thing that happens when this page loads is actually easy to miss if you’re not looking for it. At the end of the include for the Google API library is a parameter that points to a local javascript function that should be run when the library is finished loading.

var CLIENT_ID = 'YOUT_CLIENT_ID';
var SCOPES = ['https://www.googleapis.com/auth/drive.metadata.readonly'];

function checkAuth() {
  gapi.auth.authorize(
    {
      'client_id': CLIENT_ID,
      'scope': SCOPES.join(' '),
      'immediate': true
    }, handleAuthResult);
}

Taking a look at the checkAuth function that is called, we can see that it begins an authorization request to google that contains the client ID you got in the last section, a set of scopes that determine what permissions you would like, an immediate option that tells the authenticator whether to authenticate immediately or wait for user input, and finally handleAuthResult which is the callback function to run once the authentication is done. Lucky for us, the google api that we included handles the difficult aspects of OAuth.

Auth Handling

function handleAuthResult(authResult) {
  var authorizeDiv = document.getElementById('authorize-div');
  if (authResult && !authResult.error) {
    // Hide auth UI, then load client library.
    authorizeDiv.style.display = 'none';
    loadDriveApi();
  } else {
    // Show auth UI, allowing the user to initiate authorization by
    // clicking authorize button.
    authorizeDiv.style.display = 'inline';
  }
}

Here things are pretty easy to follow. If the authentication results are an error, we show the div with the authorize button from earlier to prompt the user to log in with google. Otherwise, hide that authorization button and fully load their Drive API example. Here, it’s good to note that this auth handler is the same one that’s called whether it’s from the page loading, or from the user clicking the auth button. The only difference is that with the button, the immediate property of the authorize call is set to false which prompts the user to enter their login info. Now, onto what happens when the login information is all good to go.

Loading Drive

function loadDriveApi() {
  gapi.client.load('drive', 'v3', listFiles);
}

There we go! There’s the drive aspect loading for the first time! Here, we load version 3 of the Drive API and this time set a callback to a function called listFiles that is run once the client is finished loading.

Listing Files

function listFiles() {
  var request = gapi.client.drive.files.list({
    'pageSize': 10,
    'fields': "nextPageToken, files(id, name)"
  });

  request.execute(function(resp) {
    appendPre('Files:');
    var files = resp.files;
    if (files && files.length > 0) {
      for (var i = 0; i < files.length; i++) {
        var file = files[i];
        appendPre(file.name + ' (' + file.id + ')');
      }
    } else {
      appendPre('No files found.');
    }
  });
}

The callback listFiles shows us how to actually get file information back from the API now. First, we formulate a request, in this case for files only, with a results list ten long at max, a token that will let us “browse” to the next ten results, and what metadata from the files we want returned. Then, we execute the request. An inline response handler takes the file results and prints their names and fileIDs to the webpage in the preformatted block mentioned at the beginning.

That’s it! This hundred line html and javascript file is all that’s needed to get someone up and running. Below you can see images of what the page looks like throughout this loading process. Again, beneath that is this source code as a full document so you can play with it yourself. Get ready to have fun playing with the contents of a drive coming up next!

<html>
  <head>
    <script type="text/javascript">
      // Your Client ID can be retrieved from your project in the Google
      // Developer Console, https://console.developers.google.com
      var CLIENT_ID = 'YOUR_CLIENT_ID';

      var SCOPES = ['https://www.googleapis.com/auth/drive.metadata.readonly'];

      /**
       * Check if current user has authorized this application.
       */
      function checkAuth() {
        gapi.auth.authorize(
          {
            'client_id': CLIENT_ID,
            'scope': SCOPES.join(' '),
            'immediate': true
          }, handleAuthResult);
      }

      /**
       * Handle response from authorization server.
       *
       * @param {Object} authResult Authorization result.
       */
      function handleAuthResult(authResult) {
        var authorizeDiv = document.getElementById('authorize-div');
        if (authResult && !authResult.error) {
          // Hide auth UI, then load client library.
          authorizeDiv.style.display = 'none';
          loadDriveApi();
        } else {
          // Show auth UI, allowing the user to initiate authorization by
          // clicking authorize button.
          authorizeDiv.style.display = 'inline';
        }
      }

      /**
       * Initiate auth flow in response to user clicking authorize button.
       *
       * @param {Event} event Button click event.
       */
      function handleAuthClick(event) {
        gapi.auth.authorize(
          {client_id: CLIENT_ID, scope: SCOPES, immediate: false},
          handleAuthResult);
        return false;
      }

      /**
       * Load Drive API client library.
       */
      function loadDriveApi() {
        gapi.client.load('drive', 'v3', listFiles);
      }

      /**
       * Print files.
       */
      function listFiles() {
        var request = gapi.client.drive.files.list({
            'pageSize': 10,
            'fields': "nextPageToken, files(id, name)"
          });

          request.execute(function(resp) {
            appendPre('Files:');
            var files = resp.files;
            if (files && files.length > 0) {
              for (var i = 0; i < files.length; i++) {
                var file = files[i];
                appendPre(file.name + ' (' + file.id + ')');
              }
            } else {
              appendPre('No files found.');
            }
          });
      }

      /**
       * Append a pre element to the body containing the given message
       * as its text node.
       *
       * @param {string} message Text to be placed in pre element.
       */
      function appendPre(message) {
        var pre = document.getElementById('output');
        var textContent = document.createTextNode(message + '\n');
        pre.appendChild(textContent);
      }

    </script>
    <script src="https://apis.google.com/js/client.js?onload=checkAuth">
    </script>
  </head>
  <body>
    <div id="authorize-div" style="display: none">
      <span>Authorize access to Drive API</span>
      <!--Button for the user to click to initiate auth sequence -->
      <button id="authorize-button" onclick="handleAuthClick(event)">
        Authorize
      </button>
    </div>
    <pre id="output"></pre>
  </body>
</html>