Google-Daten-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. Außerdem sollten Sie mit JavaScript vertraut sein und ein wenig Erfahrung mit der Implementierung eines OpenSocial-Gadgets mit den Gadgets.* API.

Dieses Beispiel zeigt auch, wie Sie externe Bibliotheken in Ihren Gadgets verwenden können. Ich habe jQuery (hauptsächlich für die UI-Effekte) und TinyMCE verwendet, ein tolles WYSIWYG-RTF-Plug-in.

Ziel

Für die Erstellung eines Gadgets, das JSON mit einer der Google Data APIs verwendet, ist nur sehr wenig JavaScript erforderlich. Das Äußere 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 (was eine Authentifizierung erfordert). Bisher war die Nutzung der Google Account APIs noch nicht optimal. AuthSub erfordert Browserweiterleitungen und ClientLogin stellt die Anmeldedaten eines Nutzers clientseitig bereit. Auch das Hacken eines type="url"-Gadgets war umständlich.

Geben Sie den OAuth-Proxy ein.

OAuth-Proxy

Wenn Sie OAuth nicht kennen, ist das ein Authentifizierungsstandard, mit dem ein Nutzer seine privaten Daten mit anderen Websites oder Gadgets teilen kann. Die OAuth-Spezifikation erfordert, dass alle Datenanfragen digital signiert sind. Das ist sicher, aber aus Sicherheitsgründen ist es nicht sicher, private Schlüssel zu verwalten und digitale Signaturen zu erstellen. Hinzu kommt die zusätzliche Komplikation bei domainübergreifenden Problemen.

Glücklicherweise werden diese Probleme durch die Nutzung der OAuth-Proxy-Funktion der Gadget-Plattform gelöst. Der OAuth-Proxy erleichtert Entwicklern das Leben. Er blendet weitestgehend die OAuth-Authentifizierungsdetails aus und übernimmt den Rest. Der Proxy signiert Datenanfragen im Namen Ihres Gadgets, sodass Sie keine privaten Schlüssel verwalten und sich keine Gedanken über das Signieren von Anfragen machen müssen. Es funktioniert einfach!

Der OAuth-Proxy basiert auf dem Open-Source-Projekt Shindig, einer Implementierung der Gadget-Spezifikation.

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

Erste Schritte

Im weiteren Verlauf dieser Anleitung geht es um das Erstellen eines Gadgets für den Zugriff auf die Blogger-Daten eines Nutzers. Wir authentifizieren uns mit dem OAuth-Proxy, verwenden die JavaScript-Clientbibliothek und posten schließlich einen Eintrag in Blogger.

Authentifizierung

Zuerst müssen wir das Gadget anweisen, OAuth zu verwenden. Fügen Sie dazu das Element <OAuth> im Abschnitt <ModulePrefs> 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. Erläuterung der Suchparameter:

  • scope

    Dieser Parameter ist in der Anfrage-URL erforderlich. Ihr Gadget kann nur auf Daten der in diesem Parameter verwendeten scope zugreifen. In diesem Beispiel greift das Gadget auf Blogger zu. Wenn Sie über Ihr Gadget auf mehr als eine Google Data API zugreifen möchten, können Sie die zusätzlichen scope mit einem %20 verketten. Wenn Sie beispielsweise auf Google Kalender und Blogger zugreifen möchten, legen Sie den Umfang 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 leitet zu dieser URL weiter, nachdem der Benutzer den Zugriff auf seine Daten genehmigt hat. Du kannst diesen Parameter weglassen, auf deine eigene genehmigte Seite festlegen oder vorzugsweise http://oauth.gmodules.com/gadgets/oauthcallback verwenden. Später bietet er die beste Nutzererfahrung, wenn Nutzer Ihr Gadget zum ersten Mal installieren. Diese Seite enthält ein JavaScript-Snippet, das das Pop-up-Fenster automatisch schließt.

Da unser Gadget nun OAuth verwendet, muss der Nutzer den Zugriff auf seine Daten genehmigen. So sieht der Authentifizierungsvorgang aus:

  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. Im Gadget wird „In Blogger anmelden“ angezeigt und das Attribut href wird auf den Wert von oauthApprovalUrl gesetzt.
  3. Anschließend klickt der Nutzer auf „In Blogger anmelden“ und die OAuth-Genehmigungsseite wird in einem separaten Fenster geöffnet. Das Gadget wartet, bis der Nutzer den Genehmigungsprozess abgeschlossen hat, indem er einen Link anzeigt: "Ich habe Zugriff genehmigt."
  4. Im Pop-up-Fenster wird dem Nutzer der Zugriff auf unser Gadget gewährt bzw. verweigert. Wenn sie auf „Zugriff erlauben“ klicken, werden sie zu http://oauth.gmodules.com/gadgets/oauthcallback weitergeleitet und das Fenster wird geschlossen.
  5. Das Gadget erkennt, dass das Fenster geschlossen wurde, und versucht erneut, auf Blogger zuzugreifen, indem es die Daten des Nutzers noch einmal anfordert. Ich habe einen Pop-up-Handler verwendet, um das Schließen des Fensters zu erkennen. Wenn Sie solchen Code nicht verwenden, kann der Nutzer manuell auf „Ich habe Zugriff gewährt“ klicken.
  6. Das Gadget zeigt jetzt seine normale Benutzeroberfläche an. Diese Ansicht bleibt bestehen, bis das Authentifizierungstoken unter IssuedAuthSubTokens widerrufen wird.

In den obigen Schritten haben Gadgets drei verschiedene Zustände:

  1. Nicht authentifiziert. Der Nutzer muss den Genehmigungsprozess starten.
  2. Warten, bis der Nutzer den Zugriff auf seine Daten genehmigt.
  3. Authentifiziert. In den Gadgets wird der Normalzustand angezeigt.

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>

Jede <div> wird allein mithilfe von showOnly() angezeigt. Weitere Informationen zu dieser Funktion finden Sie im vollständigen Beispiel-Gadget.

JavaScript-Clientbibliothek verwenden

Um Remote-Inhalte in OpenSocial abzurufen, führen Sie einen Aufruf der gadgets.io.makeRequest-Methode mithilfe der gadgets.* API aus. Da wir gerade ein Google Data-Gadget erstellen, brauchen Sie die gadgets.io.* APIs nicht zu berühren. Nutzen Sie stattdessen die JavaScript-Clientbibliothek, die spezielle Methoden zum Senden von Anfragen an jeden Google Data-Dienst bietet.

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

Bibliothek laden

Fügen Sie zum Laden der JavaScript-Bibliothek den allgemeinen Loader in den Abschnitt <Content> ein und importieren Sie die Bibliothek, nachdem das Gadget initialisiert wurde. Wenn Sie einen Callback an gadgets.util.registerOnLoadHandler() senden, können Sie feststellen, 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>

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 durch Aufrufen von fetchData() abzurufen. Diese Methode ist unten definiert.

Daten abrufen

Nun, da alles eingerichtet ist, wie können wir GET- oder POST-Daten in Blogger importieren?

Ein gängiges Konzept in OpenSocial ist die Definition einer Funktion namens fetchData() in Ihrem Gadget. Diese Methode verarbeitet normalerweise die verschiedenen Authentifizierungsphasen 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);
}

Wenn diese Funktion zum zweiten Mal aufgerufen wird, enthält response.feed Daten.

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

Eintrag in Blogger posten

Im letzten Schritt posten Sie einen neuen Eintrag 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, mit denen Sie ein Gadget auf den Google Data APIs codieren können.

Wir hoffen, dass Ihnen dieser Artikel gefallen hat. Die Kombination dieses Power-Tools mit der JavaScript-Client-Bibliothek von Google Data macht es Ihnen einfach, interessante, interaktive und hochentwickelte Gadgets zu erstellen.

Falls Sie Fragen oder Anmerkungen zu diesem Artikel haben, besuchen Sie uns im Diskussionsforum zu Google Accounts APIs.

Ressourcen