Creazione di un gadget di dati di Google

Eric Bidelman, team delle API di dati di Google
ottobre 2008

Introduzione

Pubblico

Questo articolo illustra come creare un gadget di Blogger. Si presume che tu abbia familiarità con le API di dati di Google e la libreria client di JavaScript. Dovresti anche conoscere bene JavaScript e avere esperienza nell'implementazione di un gadget OpenSocial utilizzando i gadget.* ".

Questo esempio mostra anche come utilizzare correttamente le librerie esterne nei gadget. Ho utilizzato jQuery (principalmente per gli effetti dell'interfaccia utente) e TinyMCE, un ottimo plug-in dell'editor RTF di WYSIWYG.

Motivazione

Basta un pochissimo JavaScript per creare un gadget che utilizzi JSON con una delle API di dati di Google. Il principale problema di questo gadget è che i dati sono pubblici e di sola lettura. Per creare gadget più interessanti, devi poter accedere ai dati privati dell'utente (operazione che richiede l'autenticazione). Finora, non esistevano un ottimo modo per utilizzare le API Google Account. AuthSub richiede reindirizzamenti del browser e ClientLogin espone le credenziali di un utente sul lato client. Anche la compromissione di un gadget type="url" è stata scomoda.

Inserisci il proxy OAuth.

Proxy OAuth

Se non hai familiarità con OAuth, è uno standard di autenticazione che consente a un utente di condividere i propri dati privati con un altro sito web o gadget. La specifica OAuth richiede che tutte le richieste di dati siano firmate digitalmente. È un'ottima soluzione per la sicurezza, ma nel caso di un gadget JavaScript la gestione delle chiavi private e la creazione di firme digitali non sono sicure. C'è anche l'ulteriore complicazione dei problemi tra domini.

Fortunatamente, questi problemi sono stati risolti grazie a una funzionalità della piattaforma di gadget chiamata Proxy OAuth. Il proxy OAuth è progettato per semplificare la vita degli sviluppatori di gadget. Nasconde molti dei dettagli di autenticazione di OAuth ed esegue le operazioni più complesse per te. Il proxy firma le richieste di dati per conto del tuo gadget, quindi non è necessario gestire le chiavi private o preoccuparti di firmare le richieste. Funziona!

Il proxy OAuth si basa su un progetto open source denominato Shindig, che è un'implementazione della specifica dei gadget.

Nota: il proxy OAuth è supportato solo per i gadget che utilizzano l'API gadgets.* ed sono in esecuzione in container OpenSocial. Non è supportato per l'API legacy dei gadget.

Per iniziare

Il resto di questo tutorial sarà incentrato sulla creazione di un gadget per accedere ai dati di Blogger di un utente. Esamineremo l'autenticazione (utilizzando il proxy OAuth), utilizzando la libreria client JavaScript e infine pubblicheremo una voce su Blogger.

Autenticazione

Per prima cosa, dobbiamo comunicare al gadget di utilizzare OAuth. A questo scopo, aggiungi l'elemento <OAuth> nella sezione <ModulePrefs> del gadget:

<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>

I tre endpoint URL nell'elemento <Service> corrispondono agli endpoint dei token OAuth di Google. Ecco la spiegazione dei parametri di ricerca:

  • scope

    Questo parametro è obbligatorio nell'URL della richiesta. Il tuo gadget potrà accedere solo ai dati dei scope utilizzati in questo parametro. In questo esempio, il gadget accederà a Blogger. Se il tuo gadget voleva accedere a più di Google API dati, concatena gli scope aggiuntivi con un %20. Ad esempio, se vuoi accedere sia a Calendar sia a Blogger, imposta l'ambito su http://www.blogger.com/feeds/%20http://www.google.com/calendar/feeds/.

  • oauth_callback

    Questo parametro è facoltativo nell'URL di autorizzazione. La pagina di approvazione OAuth reindirizzerà a questo URL dopo che l'utente avrà approvato l'accesso ai propri dati. Puoi scegliere di lasciare invariato questo parametro, impostarlo sulla tua "pagina approvata" o, preferibilmente, utilizzare http://oauth.gmodules.com/gadgets/oauthcallback. In seguito potrai usufruire della migliore esperienza utente quando gli utenti installano per la prima volta il tuo gadget. Questa pagina fornisce uno snippet di JavaScript che chiude automaticamente la finestra popup.

Ora che abbiamo il nostro gadget utilizzando OAuth, l'utente deve approvare l'accesso ai propri dati. Ecco il flusso di autenticazione:

  1. Il gadget viene caricato per la prima volta e tenta di accedere ai dati di Blogger dell'utente.
  2. La richiesta non va a buon fine perché l'utente non ha concesso l'accesso al gadget. Fortunatamente, l'oggetto restituito nella risposta contiene un URL (response.oauthApprovalUrl) a cui invieremo l'accesso all'utente. Il gadget mostra "Accedi a Blogger" e imposta il suo href sul valore di oauthApprovalUrl.
  3. Successivamente, l'utente fa clic su "Accedi a Blogger" e la pagina di approvazione di OAuth si apre in una finestra separata. Il gadget attende che l'utente termini il processo di approvazione visualizzando un link: "Ho approvato l'accesso".
  4. Nel popup, l'utente sceglierà di concedere o negare l'accesso al nostro gadget. Dopo aver fatto clic su "Concedi l'accesso", vengono indirizzati a http://oauth.gmodules.com/gadgets/oauthcallback e la finestra si chiude.
  5. Il gadget riconosce la finestra chiusa e tenta di accedere a Blogger una seconda volta richiedendo nuovamente i dati dell'utente. Per rilevare la chiusura della finestra, ho utilizzato un gestore di popup. Se non utilizzi questo codice, l'utente può fare clic manualmente su "Ho approvato l'accesso".
  6. Il gadget ora mostra la sua normale interfaccia utente. Questa visualizzazione persisterà, a meno che il token di autenticazione non venga revocato in IssuedAuthSubTokens.

Pertanto, dai passaggi precedenti, i gadget prendono in considerazione tre stati diversi:

  1. Non autenticati. L'utente deve avviare la procedura di approvazione.
  2. In attesa che l'utente approvi l'accesso ai propri dati.
  3. Autenticazione effettuata. Il gadget mostra il suo normale stato di funzionamento.

Nel mio gadget, ho utilizzato <div> container per separare ciascuna fase:

<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>

Ogni <div> viene visualizzato da solo utilizzando showOnly(). Per informazioni dettagliate sulla funzione, consulta l'esempio di gadget completo.

usando la libreria client JavaScript.

Per recuperare i contenuti remoti in OpenSocial, chiama il metodo gadgets.io.makeRequest utilizzando l'API gadgets.*. Tuttavia, poiché stiamo creando un gadget Google Data, non è necessario toccare le API gadgets.io.*. Usa la libreria client JavaScript, che invece ha metodi speciali per effettuare richieste a ciascun servizio dati Google.

Nota: al momento della stesura di questo articolo, la libreria JavaScript supporta solo Blogger, Calendar, Contatti, Finanza e Google Base. Per utilizzare una delle altre API, usa gadgets.io.makeRequest senza libreria.

Caricamento della raccolta in corso...

Per caricare la libreria JavaScript, includi il caricatore comune nella sezione <Content> e importa la libreria una volta che il gadget è stato inizializzato. Inviare un callback a gadgets.util.registerOnLoadHandler() aiuterà a determinare quando il gadget è pronto:

<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>

La chiamata a blogger.useOAuth('google') indica alla libreria di utilizzare il proxy OAuth (anziché AuthSubJS, il suo normale metodo di autenticazione). Infine, il gadget cerca di recuperare i dati di Blogger dell'utente chiamando fetchData(). Questo metodo è definito di seguito.

Recupero dati

Ora che la configurazione è stata completata, come possiamo inviare GET o POST dati a Blogger?

Un paradigma comune in OpenSocial è definire una funzione chiamata fetchData() nel tuo gadget. Questo metodo in genere gestisce le diverse fasi di autenticazione e recupera i dati utilizzando gadgets.io.makeRequest. Poiché stiamo utilizzando la libreria client JavaScript, gadgets.io.makeRequest viene sostituita da una chiamata al numero blogger.getBlogFeed():

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);
}

La seconda volta che questa funzione viene chiamata, response.feed contiene dati.

Nota: getBlogFeed() utilizza la stessa funzione per il gestore di callback e di errori.

Pubblicare una voce in Blogger

L'ultimo passaggio è pubblicare una nuova voce in un blog. Il codice seguente mostra cosa succede quando l'utente fa clic sul pulsante "Salva".

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);
}

Conclusione

Ora hai gli elementi fondamentali per iniziare a programmare un gadget sopra le API di dati di Google.

Ci auguriamo che questo articolo ti abbia dato un apprezzamento per la semplicità con cui il proxy OAuth rende l'autenticazione dei gadget. Combinando questo strumento di potenza con la libreria client di JavaScript di Google Data, è facile creare gadget interessanti, interattivi e sofisticati.

In caso di domande o commenti su questo articolo, visita il forum di discussione delle API degli Account Google.

Risorse