Google Data Gadget erstellen

Eric Bidelman, Google Data APIs-Team
Oktober 2008

Einführung

Zielgruppe

In diesem Artikel erfahren Sie, wie Sie ein Blogger-Gadget erstellen. Es wird davon ausgegangen, dass Sie mit den Google Data APIs und der JavaScript-Clientbibliothek vertraut sind. Sie sollten außerdem fließend JavaScript sprechen und etwas Erfahrung mit der Implementierung eines OpenSocial-Gadgets mit gadgets.* API.

In diesem Beispiel wird auch gezeigt, wie Sie externe Bibliotheken in Ihren Gadgets verwenden können. Ich habe jQuery (hauptsächlich für die UI-Effekte) und TinyMCE verwendet, ein großartiges WYSIWYG-Plugin für Rich-Text-Editoren.

Motivation

Es ist nur sehr wenig JavaScript erforderlich, um ein Gadget zu erstellen, das JSON mit einer der Google Data APIs verwendet. Der größte Nachteil eines solchen Gadgets ist, dass die Daten öffentlich und schreibgeschützt sind. Um interessantere Gadgets zu erstellen, benötigen Sie Zugriff auf die privaten Daten eines Nutzers. Dazu ist eine Authentifizierung erforderlich. Bisher gab es keine gute Möglichkeit, die Google Account APIs zu nutzen. AuthSub erfordert Browserweiterleitungen und ClientLogin gibt die Anmeldedaten eines Nutzers clientseitig preis. Selbst das Hacken eines type="url"-Gadgets war umständlich.

Geben Sie den OAuth-Proxy ein.

OAuth-Proxy

OAuth ist ein Authentifizierungsstandard, mit dem Nutzer ihre privaten Daten für eine andere Website oder ein anderes Gadget freigeben können. Die OAuth-Spezifikation erfordert, dass alle Datenanfragen digital signiert werden. Das ist zwar gut für die Sicherheit, aber im Fall eines JavaScript-Gadgets ist die Verwaltung privater Schlüssel und die Erstellung digitaler Signaturen unsicher. Hinzu kommen die Komplikationen, die durch domainübergreifende Probleme entstehen.

Glücklicherweise lassen sich diese Probleme mit einer Funktion der Gadget-Plattform namens OAuth-Proxy lösen. Der OAuth-Proxy soll Gadget-Entwicklern das Leben erleichtern. Dadurch werden viele Authentifizierungsdetails von OAuth ausgeblendet und die Hauptarbeit für Sie erledigt. Der Proxy signiert Datenanfragen im Namen Ihres Gadgets. Sie müssen also keine privaten Schlüssel verwalten oder sich um das Signieren von Anfragen kümmern. Es funktioniert einfach!

Der OAuth-Proxy basiert auf einem Open-Source-Projekt namens Shindig, das eine Implementierung der Gadget-Spezifikation ist.

Hinweis : Der OAuth-Proxy wird nur für Gadgets unterstützt, die die gadgets.* API verwenden und in OpenSocial-Containern ausgeführt werden. Sie wird für die Legacy Gadgets API nicht unterstützt.

Erste Schritte

Im weiteren Verlauf dieser Anleitung geht es darum, ein Gadget für den Zugriff auf die Blogger-Daten eines Nutzers zu erstellen. Wir gehen die Authentifizierung (mit dem OAuth-Proxy), die Verwendung der JavaScript-Clientbibliothek und schließlich das Posten eines Eintrags in Blogger durch.

Authentifizierung

Zuerst müssen wir dem Gadget mitteilen, dass es OAuth verwenden soll. Fügen Sie dazu das <OAuth>-Element im <ModulePrefs>-Abschnitt des Gadgets hinzu:

<ModulePrefs>
...
<OAuth>
  <Service name="google">
    <Access url="https://www.google.com/accounts/OAuthGetAccessToken" method="GET" /> 
    <Request url="https://www.google.com/accounts/OAuthGetRequestToken?scope=http://www.blogger.com/feeds/" method="GET" /> 
    <Authorization url="https://www.google.com/accounts/OAuthAuthorizeToken?
                        oauth_callback=http://oauth.gmodules.com/gadgets/oauthcallback" /> 
  </Service>
</OAuth>
...
</ModulePrefs>

Die drei URL-Endpunkte im <Service>-Element entsprechen den OAuth-Token-Endpunkten von Google. Hier finden Sie eine Erklärung der Abfrageparameter:

  • scope

    Dieser Parameter ist in der Anforderungs-URL erforderlich. Ihr Gadget kann nur auf Daten der scope zugreifen, die in diesem Parameter verwendet werden. In diesem Beispiel greift das Gadget auf Blogger zu. Wenn Ihr Gadget auf mehr als eine Google Data API zugreifen soll, hängen Sie die zusätzlichen scope mit einem %20 an. Wenn Sie beispielsweise sowohl auf Google Kalender als auch auf Blogger zugreifen möchten, legen Sie den Bereich auf http://www.blogger.com/feeds/%20http://www.google.com/calendar/feeds/ fest.

  • oauth_callback

    Dieser Parameter ist in der Autorisierungs-URL optional. Die OAuth-Genehmigungsseite wird an diese URL weitergeleitet, nachdem der Nutzer den Zugriff auf seine Daten genehmigt hat. Sie können diesen Parameter weglassen, auf Ihre eigene „genehmigte Seite“ festlegen oder vorzugsweise http://oauth.gmodules.com/gadgets/oauthcallback verwenden. Letzteres bietet die beste Nutzererfahrung, wenn Nutzer Ihr Gadget zum ersten Mal installieren. Auf dieser Seite finden Sie ein JavaScript-Snippet, mit dem das Pop-up-Fenster automatisch geschlossen wird.

Nachdem wir unser Gadget mit OAuth eingerichtet haben, muss der Nutzer den Zugriff auf seine Daten genehmigen. So funktioniert die Authentifizierung:

  1. Das Gadget wird zum ersten Mal geladen und versucht, auf die Blogger-Daten des Nutzers zuzugreifen.
  2. Die Anfrage schlägt fehl, weil der Nutzer keinen Zugriff auf das Gadget gewährt hat. Glücklicherweise enthält das in der Antwort zurückgegebene Objekt eine URL (response.oauthApprovalUrl), an die wir den Nutzer zur Anmeldung weiterleiten. Das Gadget zeigt „In Blogger anmelden“ an und legt den href-Wert auf den Wert von oauthApprovalUrl fest.
  3. Als Nächstes klickt der Nutzer auf „In Blogger anmelden“. Die OAuth-Genehmigungsseite wird in einem separaten Fenster geöffnet. Das Gadget wartet darauf, dass der Nutzer den Genehmigungsprozess abschließt, und zeigt den Link „Zugriff genehmigt“ an.
  4. Im Pop-up-Fenster kann der Nutzer den Zugriff auf unser Gadget gewähren oder verweigern. Wenn der Nutzer auf „Zugriff gewähren“ klickt, wird er zu http://oauth.gmodules.com/gadgets/oauthcallback weitergeleitet und das Fenster wird geschlossen.
  5. Das Gadget erkennt, dass das Fenster geschlossen wurde, und versucht ein zweites Mal, auf Blogger zuzugreifen, indem es die Daten des Nutzers noch einmal anfordert. Um das Schließen des Fensters zu erkennen, habe ich einen Pop-up-Handler verwendet. Wenn Sie keinen solchen Code verwenden, kann der Nutzer manuell auf „Zugriff genehmigt“ klicken.
  6. Das Gadget zeigt jetzt seine normale Benutzeroberfläche an. Diese Ansicht bleibt bestehen, sofern das Authentifizierungstoken nicht unter IssuedAuthSubTokens widerrufen wird.

Aus den obigen Schritten geht hervor, dass Gadgets drei verschiedene Status haben:

  1. Nicht authentifiziert. Der Nutzer muss den Genehmigungsprozess starten.
  2. Es wird darauf gewartet, dass der Nutzer den Zugriff auf seine Daten genehmigt.
  3. Authentifiziert. Das Gadget zeigt seinen normalen Funktionszustand an.

In meinem Gadget habe ich <div>-Container verwendet, um die einzelnen Phasen zu trennen:

<Content type="html">
<![CDATA[

<!-- Normal state of the gadget. The user is authenticated -->       
<div id="main" style="display:none">
  <form id="postForm" name="postForm" onsubmit="savePost(this); return false;">
     <div id="messages" style="display: none"></div>
     <div class="selectFeed">Publish to:
       <select id="postFeedUri" name="postFeedUri" disabled="disabled"><option>loading blog list...</option></select>
     </div>
     <h4 style="clear:both">Title</h4>
     <input type="text" id="title" name="title"/>
     <h4>Content</h4>
     <textarea id="content" name="content" style="width:100%;height:200px;"></textarea>
     <h4 style="float:left;">Labels (comma separated)</h4><img src="blogger.png" style="float:right"/>
     <input type="text" id="categories" name="categories"/>
     <p><input type="submit" id="submitButton" value="Save"/> 
     <input type="checkbox" id="draft" name="draft" checked="checked"/> <label for="draft">Draft?</label></p>
  </form>
</div>

<div id="approval" style="display: none">
  <a href="#" id="personalize">Sign in to Blogger</a>
</div>

<div id="waiting" style="display: none">
  <a href="#" id="approvalLink">I've approved access</a>
</di

<!-- An errors section is not necessary but great to have -->
<div id="errors" style="display: none"></div>
 
<!-- Also not necessary, but great for informing users -->     
<div id="loading">
  <h3>Loading...</h3>
  <p><img src="ajax-loader.gif"></p>
</div>

]]> 
</Content&gt

Jeder <div> wird mit showOnly() einzeln dargestellt. Weitere Informationen zu dieser Funktion finden Sie im vollständigen Beispiel-Gadget.

JavaScript-Clientbibliothek verwenden

Wenn Sie Remoteinhalte in OpenSocial abrufen möchten, rufen Sie die Methode gadgets.io.makeRequest über die gadgets.* API auf. Da wir jedoch ein Google Data-Gadget erstellen, müssen wir die gadgets.io.*-APIs nicht verwenden. Verwenden Sie stattdessen die JavaScript-Clientbibliothek, die spezielle Methoden zum Senden von Anfragen an die einzelnen Google Data-Dienste enthält.

Hinweis: Zum Zeitpunkt der Erstellung dieses Artikels unterstützt die JavaScript-Bibliothek nur Blogger, Calendar, Kontakte, Finance und Google Base. Wenn Sie eine der anderen APIs verwenden möchten, verwenden Sie gadgets.io.makeRequest ohne die Bibliothek.

Bibliothek laden

Um die JavaScript-Bibliothek zu laden, fügen Sie das gemeinsame Ladeprogramm in den <Content>-Abschnitt ein und importieren Sie die Bibliothek, sobald das Gadget initialisiert wurde. Wenn Sie gadgets.util.registerOnLoadHandler() einen Callback übergeben, können Sie ermitteln, wann das Gadget bereit ist:

<Content type="html">
<![CDATA[
  ...
  <script src="https://www.google.com/jsapi"></script>
  <script type="text/javascript">
  var blogger = null;  // make our service object global for later
  
  // Load the JS library and try to fetch data once it's ready
  function initGadget() {  
    google.load('gdata', '1.x', {packages: ['blogger']});  // Save overhead, only load the Blogger service
    google.setOnLoadCallback(function () {
      blogger = new google.gdata.blogger.BloggerService('google-BloggerGadget-v1.0');
      blogger.useOAuth('google');
      fetchData();
    });
  }
  gadgets.util.registerOnLoadHandler(initGadget);
  </script>
  ...
]]> 
</Content&gt

Der Aufruf von blogger.useOAuth('google') weist die Bibliothek an, den OAuth-Proxy anstelle von AuthSubJS (der normalen Authentifizierungsmethode) zu verwenden. Schließlich versucht das Gadget, die Blogger-Daten des Nutzers abzurufen, indem es fetchData() aufruft. Diese Methode wird unten definiert.

Daten abrufen

Nachdem alles eingerichtet ist, wie GET oder POST wir Daten in Blogger?

Ein gängiges Paradigma in OpenSocial ist es, in Ihrem Gadget eine Funktion namens fetchData() zu definieren. Diese Methode verarbeitet in der Regel die verschiedenen Phasen der Authentifizierung und ruft Daten mit gadgets.io.makeRequest ab. Da wir die JavaScript-Clientbibliothek verwenden, wird gadgets.io.makeRequest durch einen Aufruf von blogger.getBlogFeed() ersetzt:

function fetchData() {
  jQuery('#errors').hide();
  
  var callback = function(response) {
    if (response.oauthApprovalUrl) {
      // You can set the sign in link directly:
      // jQuery('#personalize').get(0).href = response.oauthApprovalUrl
      
      // OR use the popup.js handler
      var popup = shindig.oauth.popup({
        destination: response.oauthApprovalUrl,
        windowOptions: 'height=600,width=800',
        onOpen: function() {
          showOnly('waiting');
        },
        onClose: function() {
          showOnly('loading');
          fetchData();
        }
      });
      jQuery('#personalize').get(0).onclick = popup.createOpenerOnClick();
      jQuery('#approvalLink').get(0).onclick = popup.createApprovedOnClick();
      
      showOnly('approval');
    } else if (response.feed) {
      showResults(response);
      showOnly('main');
    } else {
      jQuery('#errors').html('Something went wrong').fadeIn();
      showOnly('errors');
    }
  };
  
  blogger.getBlogFeed('http://www.blogger.com/feeds/default/blogs', callback, callback);
}

Beim zweiten Aufruf dieser Funktion enthält response.feed Daten.

Hinweis: getBlogFeed() verwendet dieselbe Funktion für den Callback und den Fehler-Handler.

Beitrag in Blogger posten

Der letzte Schritt ist das Posten eines neuen Eintrags in einem Blog. Der folgende Code zeigt, was passiert, wenn der Nutzer auf die Schaltfläche „Speichern“ klickt.

function savePost(form) { 
  jQuery('#messages').fadeOut();
  jQuery('#submitButton').val('Publishing...').attr('disabled', 'disabled');
  
  // trim whitespace from the input tags
  var input = form.categories.value;
  var categories = jQuery.trim(input) != '' ? input.split(',') : [];   
  jQuery.each(categories, function(i, value) {
    var label = jQuery.trim(value);
    categories[i] = {
      scheme: 'http://www.blogger.com/atom/ns#',
      term: label
    };
  });

  // construct the blog post entry
  var newEntry = new google.gdata.blogger.BlogPostEntry({
    title: {
      type: 'text', 
      text: form.title.value
    },
    content: {
      type: 'text', 
      text: form.content.value
    },
    categories: categories
  });
  
  // publish as draft?
  var isDraft = form.draft.checked;
  if (isDraft) {
    newEntry.setControl({draft: {value: google.gdata.Draft.VALUE_YES}});
  }
  
  // callback for insertEntry()
  var handleInsert = function(entryRoot) {
    var entry = entryRoot.entry;
    var str = isDraft ? '(as draft)' : '<a href="' + entry.getHtmlLink().getHref() + '" target="_blankt">View it</a>';

    jQuery('#messages').html('Post published! ' + str).fadeIn();
    jQuery('#submitButton').val('Save').removeAttr('disabled');
  };
  
  // error handler for insertEntry()
  var handleError = function(e) {
    var msg = e.cause ? e.cause.statusText + ': ' : '';
    msg += e.message;
    alert('Error: ' + msg);
  };
  
  blogger.insertEntry(form.postFeedUri.value, newEntry, handleInsert, handleError);
}

Fazit

Jetzt haben Sie die Bausteine, um ein Gadget auf Basis der Google Data APIs zu programmieren.

Wir hoffen, dass Sie in diesem Artikel einen Eindruck davon erhalten haben, wie einfach die Gadget-Authentifizierung mit dem OAuth-Proxy ist. In Kombination mit der Google Data JavaScript-Clientbibliothek lassen sich damit ganz einfach interessante, interaktive und anspruchsvolle Gadgets erstellen.

Wenn Sie Fragen oder Anmerkungen zu diesem Artikel haben, besuchen Sie bitte das Diskussionsforum für Google-Konto-APIs.

Ressourcen