Outubro de 2008
Introdução
Público-alvo
Neste artigo, vamos mostrar como criar um gadget do Blogger. Ele pressupõe que você conhece as APIs Google Data e a biblioteca de cliente JavaScript. Você também precisa ter fluência em JavaScript e experiência na implementação de um gadget OpenSocial usando o gadgets.* API.
Este exemplo também demonstra como usar bibliotecas externas nos seus gadgets. Usei jQuery (principalmente para efeitos de interface) e TinyMCE, um ótimo plug-in de editor de texto avançado WYSIWYG.
Motivação
É necessário muito pouco JavaScript para criar um gadget que usa JSON com uma das APIs de dados do Google. O maior problema desse gadget é que os dados são públicos e somente leitura. Para criar gadgets mais interessantes, é necessário acessar os dados particulares de um usuário, o que exige autenticação. Até agora, não havia uma ótima maneira de aproveitar as APIs da Conta do Google. O AuthSub exige redirecionamentos do navegador, e o ClientLogin expõe as credenciais de um usuário no lado do cliente. Até mesmo hackear um gadget type="url"
era inconveniente.
Insira o proxy do OAuth.
Proxy OAuth
Se você não conhece o OAuth, ele é um padrão de autenticação que permite que um usuário compartilhe dados particulares com outro site ou gadget. A especificação do OAuth exige que todas as solicitações de dados sejam assinadas digitalmente. Isso é ótimo para a segurança, mas, no caso de um gadget JavaScript, gerenciar chaves privadas e criar assinaturas digitais não é seguro. Há também a complicação adicional de problemas entre domínios.
Felizmente, esses problemas são resolvidos com um recurso da plataforma de gadgets chamado proxy OAuth. O proxy OAuth foi criado para facilitar a vida dos desenvolvedores de gadgets. Ele oculta grande parte dos detalhes de autenticação do OAuth e faz o trabalho pesado para você. O proxy assina solicitações de dados em nome do gadget. Assim, não é necessário gerenciar chaves privadas nem se preocupar com a assinatura de solicitações. Ele simplesmente funciona!
O proxy OAuth é baseado em um projeto de código aberto chamado Shindig, que é uma implementação da especificação de gadget.
Observação : o proxy OAuth só é compatível com gadgets que usam a API gadgets.*
e são executados em contêineres OpenSocial.
Ela não é compatível com a API de gadgets legados.
Primeiros passos
O restante deste tutorial vai se concentrar na criação de um gadget para acessar os dados do Blogger de um usuário. Vamos abordar a autenticação (usando o proxy OAuth), o uso da biblioteca de cliente JavaScript e, por fim, a postagem de uma entrada no Blogger.
Autenticação
Primeiro, precisamos dizer ao gadget para usar o OAuth. Para fazer isso, adicione o elemento <OAuth>
à seção <ModulePrefs>
do 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>
Os três endpoints de URL no elemento <Service>
correspondem aos endpoints de token OAuth do Google. Confira a explicação dos parâmetros de consulta:
scope
Esse parâmetro é obrigatório no URL da solicitação. Seu gadget só poderá acessar dados dos
scope
s usados nesse parâmetro. Neste exemplo, o gadget vai acessar o Blogger. Se o gadget quiser acessar mais de uma API de dados do Google, concatene osscope
s adicionais com um%20
. Por exemplo, se você quiser acessar o Google Agenda e o Blogger, defina o escopo comohttp://www.blogger.com/feeds/%20http://www.google.com/calendar/feeds/
.oauth_callback
Esse parâmetro é opcional no URL de autorização. A página de aprovação do OAuth vai redirecionar para esse URL depois que o usuário aprovar o acesso aos dados dele. Você pode deixar esse parâmetro de fora, definir sua própria "página aprovada" ou, de preferência, usar
http://oauth.gmodules.com/gadgets/oauthcallback
. O último oferece a melhor experiência do usuário quando os usuários instalam o gadget pela primeira vez. Essa página fornece um snippet de JavaScript que fecha automaticamente a janela pop-up.
Agora que temos nosso gadget usando o OAuth, o usuário precisa aprovar o acesso aos dados dele. Confira o fluxo de autenticação:
- O gadget é carregado pela primeira vez e tenta acessar os dados do Blogger do usuário.
- A solicitação falha porque o usuário não concedeu acesso ao gadget. Felizmente, o objeto retornado na resposta
contém um URL (
response.oauthApprovalUrl
) para onde vamos enviar o usuário para fazer login. O gadget mostra a mensagem "Fazer login no Blogger" e define o href como o valor deoauthApprovalUrl
. - Em seguida, o usuário clica em "Fazer login no Blogger", e a página de aprovação do OAuth é aberta em uma janela separada. O gadget aguarda a conclusão do processo de aprovação pelo usuário exibindo um link: "Aprovei o acesso".
- No pop-up, o usuário vai escolher conceder ou negar acesso ao nosso gadget. Depois que a pessoa clicar em "Conceder acesso", ela será redirecionada para
http://oauth.gmodules.com/gadgets/oauthcallback
e a janela será fechada. - O gadget reconhece que a janela foi fechada e tenta acessar o Blogger uma segunda vez solicitando novamente os dados do usuário. Para detectar o fechamento da janela, usei um processador de pop-up. Se você não usar esse código, o usuário poderá clicar manualmente em "Aprovei o acesso".
- O gadget agora mostra a interface normal. Essa visualização vai persistir, a menos que o token de autenticação seja revogado em IssuedAuthSubTokens.
Portanto, de acordo com as etapas acima, os gadgets têm a noção de três estados diferentes:
- Não autenticado. O usuário precisa iniciar o processo de aprovação.
- Aguardando a aprovação do acesso aos dados do usuário.
- Autenticado. Os gadgets mostram o estado funcional normal.
No meu gadget, usei contêineres <div>
para separar cada etapa:
<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>
Cada <div>
é exibido por si só usando showOnly()
. Consulte o gadget de exemplo completo para mais detalhes sobre essa função.
Como usar a biblioteca de cliente JavaScript
Para buscar conteúdo remoto no OpenSocial, faça uma chamada ao método gadgets.io.makeRequest
usando a API gadgets.*
.
No entanto, como estamos criando um gadget do Google Data, não é necessário usar as APIs gadgets.io.*
. Em vez disso, use a biblioteca de cliente JavaScript, que tem métodos especiais para fazer solicitações a cada serviço de dados do Google.
Observação: no momento em que este artigo foi escrito, a biblioteca JavaScript só era compatível com Blogger, Agenda,
Contatos,
Finanças e Google Base. Para usar uma das outras
APIs, use gadgets.io.makeRequest
sem a biblioteca.
Carregar a biblioteca
Para carregar a biblioteca JavaScript, inclua o carregador comum na seção <Content>
e importe a biblioteca
depois que o gadget for inicializado. Ao transmitir um callback para gadgets.util.registerOnLoadHandler()
, você ajuda a determinar quando o gadget está 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>
A chamada para blogger.useOAuth('google')
informa à biblioteca para usar o proxy OAuth (em vez de AuthSubJS, o método de autenticação normal).
Por fim, o gadget tenta recuperar os dados do Blogger do usuário chamando fetchData()
. Esse método é definido abaixo.
Buscando dados
Agora que tudo está configurado, como fazemos para GET
ou POST
dados para o Blogger?
Um paradigma comum no OpenSocial é definir uma função chamada fetchData()
no gadget. Esse método geralmente processa as diferentes etapas de autenticação e busca dados usando gadgets.io.makeRequest
. Como estamos usando a biblioteca de cliente JavaScript, gadgets.io.makeRequest
é substituído por uma chamada para 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); }
Na segunda vez que essa função é chamada, response.feed
contém dados.
Observação: o getBlogFeed()
usa a mesma função para o callback e o gerenciador de erros.
Postar uma entrada no Blogger
A última etapa é postar uma nova entrada em um blog. O código abaixo demonstra o que acontece quando o usuário clica no botão "Salvar".
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); }
Conclusão
Agora você tem os elementos básicos para começar a programar um gadget com base nas APIs de dados do Google.
Esperamos que este artigo tenha mostrado como o proxy OAuth simplifica a autenticação de gadgets. Ao combinar essa ferramenta poderosa com a biblioteca de cliente JavaScript de dados do Google, é fácil criar gadgets interessantes, interativos e sofisticados.
Se você tiver dúvidas ou comentários sobre este artigo, acesse o fórum de discussão das APIs de Contas do Google.
Recursos
- Como escrever gadgets OAuth (documentação completa de gadgets)
- Como usar o OAuth com as APIs Google Data (artigo sobre como usar o OAuth com as APIs Google Data)
- Autenticação OAuth para aplicativos da Web (documentação completa do OAuth)
- Biblioteca de cliente JavaScript
- Fórum de discussão sobre as APIs Google Accounts