Octobre 2008
Introduction
Audience
Cet article vous explique comment créer un gadget Blogger. Il suppose que vous connaissez les API Google Data et la bibliothèque cliente JavaScript. Vous devez également maîtriser JavaScript et avoir une certaine expérience de l'implémentation d'un gadget OpenSocial à l'aide de gadgets.* API.
Cet exemple montre également comment utiliser correctement des bibliothèques externes dans vos gadgets. J'ai utilisé jQuery (principalement pour ses effets d'interface utilisateur) et TinyMCE, un excellent plug-in d'éditeur de texte enrichi WYSIWYG.
Motivation
Il faut très peu de code JavaScript pour créer un gadget qui utilise JSON avec l'une des API Google Data. Le principal inconvénient de ce gadget est que les données sont publiques et en lecture seule. Pour créer des gadgets plus intéressants, vous devez accéder aux données privées d'un utilisateur (ce qui nécessite une authentification). Jusqu'à présent, il n'existait pas de moyen efficace de tirer parti des API de compte Google. AuthSub nécessite des redirections de navigateur et ClientLogin expose les identifiants d'un utilisateur côté client. Même pirater un gadget type="url"
était devenu compliqué.
Saisissez le proxy OAuth.
Proxy OAuth
Si vous ne connaissez pas OAuth, il s'agit d'une norme d'authentification qui permet à un utilisateur de partager ses données privées avec un autre site Web ou gadget. La spécification OAuth exige que toutes les demandes de données soient signées numériquement. C'est un avantage pour la sécurité, mais dans le cas d'un gadget JavaScript, la gestion des clés privées et la création de signatures numériques ne sont pas sécurisées. Les problèmes multidomaines compliquent également la situation.
Heureusement, ces problèmes sont résolus grâce à une fonctionnalité de la plate-forme de gadgets appelée "proxy OAuth". Le proxy OAuth est conçu pour faciliter la vie des développeurs de gadgets. Il masque la plupart des informations d'authentification OAuth et effectue le gros du travail pour vous. Le proxy signe les demandes de données au nom de votre gadget. Vous n'avez donc pas besoin de gérer les clés privées ni de vous soucier de la signature des demandes. Simple et efficace !
Le proxy OAuth est basé sur un projet Open Source appelé Shindig, qui est une implémentation de la spécification des gadgets.
Remarque : Le proxy OAuth n'est compatible qu'avec les gadgets utilisant l'API gadgets.*
et s'exécutant dans des conteneurs OpenSocial.
Elle n'est pas compatible avec l'ancienne API Gadgets.
Premiers pas
Le reste de ce tutoriel se concentre sur la création d'un gadget permettant d'accéder aux données Blogger d'un utilisateur. Nous allons passer en revue l'authentification (à l'aide du proxy OAuth), l'utilisation de la bibliothèque cliente JavaScript et, enfin, la publication d'une entrée sur Blogger.
Authentification
Tout d'abord, nous devons indiquer au gadget d'utiliser OAuth. Pour ce faire, ajoutez l'élément <OAuth>
dans la section <ModulePrefs>
du 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>
Les trois points de terminaison d'URL de l'élément <Service>
correspondent aux points de terminaison de jeton OAuth de Google. Voici une explication des paramètres de requête :
scope
Ce paramètre est obligatoire dans l'URL de la requête. Votre gadget ne pourra accéder qu'aux données des
scope
utilisés dans ce paramètre. Dans cet exemple, le gadget accède à Blogger. Si votre gadget souhaite accéder à plusieurs API Google Data, concaténez lesscope
supplémentaires avec un%20
. Par exemple, si vous souhaitez accéder à la fois à Agenda et à Blogger, définissez le champ d'application surhttp://www.blogger.com/feeds/%20http://www.google.com/calendar/feeds/
.oauth_callback
Ce paramètre est facultatif dans l'URL d'autorisation. La page d'approbation OAuth redirige l'utilisateur vers cette URL une fois qu'il a approuvé l'accès à ses données. Vous pouvez choisir de ne pas inclure ce paramètre, de le définir sur votre propre "page approuvée" ou, de préférence, d'utiliser
http://oauth.gmodules.com/gadgets/oauthcallback
. Cette dernière offre la meilleure expérience utilisateur lorsque les utilisateurs installent votre gadget pour la première fois. Cette page fournit un extrait de code JavaScript qui ferme automatiquement la fenêtre pop-up.
Maintenant que notre gadget utilise OAuth, l'utilisateur doit approuver l'accès à ses données. Voici le flux d'authentification :
- Le gadget se charge pour la première fois et tente d'accéder aux données Blogger de l'utilisateur.
- La requête échoue, car l'utilisateur n'a pas accordé l'accès au gadget. Heureusement, l'objet renvoyé dans la réponse contient une URL (
response.oauthApprovalUrl
) vers laquelle nous redirigerons l'utilisateur pour qu'il se connecte. Le gadget affiche "Se connecter à Blogger" et définit son href sur la valeur deoauthApprovalUrl
. - L'utilisateur clique ensuite sur "Se connecter à Blogger". La page d'approbation OAuth s'ouvre dans une fenêtre distincte. Le gadget attend que l'utilisateur termine le processus d'approbation en affichant un lien : "J'ai approuvé l'accès".
- Dans le pop-up, l'utilisateur choisit d'accorder ou de refuser l'accès à notre gadget. Une fois qu'il a cliqué sur "Accorder l'accès", il est redirigé vers
http://oauth.gmodules.com/gadgets/oauthcallback
et la fenêtre se ferme. - Le gadget reconnaît que la fenêtre est fermée et tente d'accéder à Blogger une deuxième fois en demandant à nouveau les données de l'utilisateur. Pour détecter la fermeture de la fenêtre, j'ai utilisé un gestionnaire de pop-up. Si vous n'utilisez pas ce code, l'utilisateur peut cliquer manuellement sur "J'ai approuvé l'accès".
- Le gadget affiche désormais son interface utilisateur normale. Cette vue persistera, sauf si le jeton d'authentification est révoqué sous IssuedAuthSubTokens.
Ainsi, d'après les étapes ci-dessus, les gadgets ont trois états différents :
- Non authentifié. L'utilisateur doit lancer le processus d'approbation.
- En attente de l'approbation de l'accès à ses données par l'utilisateur.
- Authentifié. Le gadget affiche son état de fonctionnement normal.
Dans mon gadget, j'ai utilisé des conteneurs <div>
pour séparer chaque étape :
<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>
Chaque <div>
est affiché seul à l'aide de showOnly()
. Pour en savoir plus sur cette fonction, consultez l'exemple complet de gadget.
Utiliser la bibliothèque cliente JavaScript
Pour extraire du contenu à distance dans OpenSocial, vous appelez la méthode gadgets.io.makeRequest
à l'aide de l'API gadgets.*
.
Toutefois, comme nous créons un gadget Google Data, il n'est pas nécessaire de toucher aux API gadgets.io.*
. Utilisez plutôt la bibliothèque cliente JavaScript, qui comporte des méthodes spéciales pour envoyer des requêtes à chaque service de données Google.
Remarque : Au moment de la rédaction de cet article, la bibliothèque JavaScript n'est compatible qu'avec Blogger, Agenda, Contacts, Finance et Google Base. Pour utiliser l'une des autres API, utilisez gadgets.io.makeRequest
sans la bibliothèque.
Charger la bibliothèque
Pour charger la bibliothèque JavaScript, incluez le chargeur commun dans la section <Content>
et importez la bibliothèque une fois le gadget initialisé. L'envoi d'un rappel à gadgets.util.registerOnLoadHandler()
permet de déterminer quand le gadget est prêt :
<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>
L'appel à blogger.useOAuth('google')
indique à la bibliothèque d'utiliser le proxy OAuth (au lieu de AuthSubJS, sa méthode d'authentification habituelle).
Enfin, le gadget tente de récupérer les données Blogger de l'utilisateur en appelant fetchData()
. Cette méthode est définie ci-dessous.
Récupération des données en cours
Maintenant que tout est configuré, comment GET
ou POST
des données sur Blogger ?
Un paradigme courant dans OpenSocial consiste à définir une fonction appelée fetchData()
dans votre gadget. Cette méthode gère généralement les différentes étapes de l'authentification et récupère les données à l'aide de gadgets.io.makeRequest
. Étant donné que nous utilisons la bibliothèque cliente JavaScript, gadgets.io.makeRequest
est remplacé par un appel à 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 deuxième fois que cette fonction est appelée, response.feed
contient des données.
Remarque : getBlogFeed()
utilise la même fonction pour son gestionnaire de rappel et d'erreurs.
Publier un article sur Blogger
La dernière étape consiste à publier un nouvel article sur un blog. Le code ci-dessous montre ce qui se passe lorsque l'utilisateur clique sur le bouton "Enregistrer".
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); }
Conclusion
Vous disposez désormais des éléments de base pour commencer à coder un gadget sur les API Google Data.
Nous espérons que cet article vous a permis de comprendre à quel point le proxy OAuth simplifie l'authentification des gadgets. En combinant cet outil puissant avec la bibliothèque cliente JavaScript Google Data, vous pouvez créer facilement des gadgets intéressants, interactifs et sophistiqués.
Si vous avez des questions ou des commentaires sur cet article, veuillez nous contacter sur le forum de discussion sur les API des comptes Google.
Ressources
- Écrire des gadgets OAuth (documentation complète sur les gadgets)
- Utiliser OAuth avec les API Google Data (article sur l'utilisation d'OAuth avec les API Google Data)
- Authentification OAuth pour les applications Web (documentation OAuth complète)
- Bibliothèque cliente JavaScript
- Forum de discussion sur les API Comptes Google