Fevereiro de 2009
Introdução
"Onde está o Ruby na lista de bibliotecas de cliente?"
Motivado pelo apetite feroz dos nossos desenvolvedores e pela popularidade duradoura do Ruby on Rail (RoR), meu colega Jeff Fisher criou uma biblioteca de utilitários do Ruby das profundezas do Monte Doom. Não se trata de uma biblioteca de cliente completa, mas ela processa os princípios básicos, como autenticação e manipulação básica de XML. Também é necessário trabalhar diretamente com o feed Atom usando o módulo REXML e o XPath.
Público-alvo
Este artigo é destinado a desenvolvedores interessados em acessar as APIs de dados do Google usando Ruby, especificamente o Ruby on Rail. Ele pressupõe que o leitor tenha alguma familiaridade com a linguagem de programação Ruby e o framework de desenvolvimento da Web do Rail. Eu me concentro na API List List para a maioria das amostras, mas os mesmos conceitos podem ser aplicados a qualquer uma das APIs de dados.
Como começar
Requisitos
Como instalar a biblioteca de utilitários do Ruby de dados do Google
Para conseguir a biblioteca, faça o download da origem da biblioteca diretamente na hospedagem do projeto ou instale a gem:
sudo gem install gdata
Dica: para uma boa avaliação, execute gem list --local
para verificar se a gem foi instalada corretamente.
Autenticação
ClientLogin
O ClientLogin permite que seu aplicativo faça o login dos usuários de forma programática na conta do Google ou do G Suite. Ao validar as credenciais do usuário, o Google emite um token Auth para ser usado em solicitações de API subsequentes. O token permanece válido por um período definido, definido por qualquer serviço do Google com que você esteja trabalhando. Por motivos de segurança e para oferecer aos usuários a melhor experiência, você só deve usar ClientLogin ao desenvolver aplicativos instalados para computadores. Para aplicativos da Web, use OAuth ou OAuth.
A biblioteca Ruby tem uma classe de cliente para cada uma das APIs. Por exemplo, use o seguinte snippet de código para fazer login em user@gmail.com
na
API Documents List Data:
client = GData::Client::DocList.new client.clientlogin('user@gmail.com', 'pa$$word')
The YouTube Data API would be:
client = GData::Client::YouTube.new client.clientlogin('user@gmail.com', 'pa$$word')
Veja a lista completa de classes de serviço implementadas.
Se um serviço não tiver uma classe de cliente, use a
classe GData::Client::Base
.
Por exemplo, o código a seguir força os usuários a fazer login com uma conta do G Suite.
client_login_handler = GData::Auth::ClientLogin
.new('writely', :account_type => 'HOSTED')
token = client_login_handler.get_token('user@example.com', 'pa$$word', 'google-RailsArticleSample-v1')
client = GData::Client::Base.new(:auth_handler => client_login_handler)
Observação: por padrão, a biblioteca usa HOSTED_OR_GOOGLE
para a accountType
. Os valores possíveis são HOSTED_OR_GOOGLE
,
HOSTED
ou GOOGLE
.
Uma das desvantagens de usar o ClientLogin é que seu aplicativo pode receber desafios CAPTCHA em tentativas de login malsucedidas. Se isso acontecer,
é possível processar o erro chamando o método clientlogin()
com os parâmetros extras:
client.clientlogin(username, password, captcha_token, captcha_answer)
. Consulte a documentação completa do Authentication para aplicativos instalados
para mais informações sobre como lidar com CAPTCHAs.
AuthSub
Como gerar o URL tmpRequest
scope = 'http://www.google.com/calendar/feeds/' next_url = 'http://example.com/change/to/your/app' secure = false # set secure = true for signed AuthSub requests sess = true authsub_link = GData::Auth::AuthSub.get_url(next_url, scope, secure, sess)
O bloco de código anterior cria o seguinte URL em authsub_link
:
https://www.google.com/accounts/AuthSubRequest?next=http%3A%2F%2Fexample.com%2Fchange%2Fto%2Fyour%2Fapp&scope=http%3A%2F%2Fwww.google.com%2Fcalendar%2Ffeeds%2F&session=1&secure=0
Também é possível usar o método authsub_url
do objeto cliente. Cada classe de serviço definiu um atributo authsub_scope
padrão, então não é necessário
especificar o seu.
client = GData::Client::DocList.new next_url = 'http://example.com/change/to/your/app' secure = false # set secure = true for signed AuthSub requests sess = true domain = 'example.com' # force users to login to a G Suite hosted domain authsub_link = client.authsub_url(next_url, secure, sess, domain)
O bloco de código anterior cria o URL a seguir:
https://www.google.com/accounts/AuthSubRequest?next=http%3A%2F%2Fexample.com%2Fchange%2Fto%2Fyour%2Fapp&scope=http%3A%2F%2Fdocs.google.com%2Ffeeds%2F&session=1&secure=0&hd=example.com
Como fazer upgrade de um token de uso único para um token de sessão
Depois de conceder acesso aos dados, o usuário vai ser redirecionado para http://example.com/change/to/your/app?token=SINGLE_USE_TOKEN
. O URL é somente nosso next_url
com o token de uso único
anexado como um parâmetro de consulta.
Em seguida, troque o token de uso único por um token de sessão de longa duração:
client.authsub_token = params[:token] # extract the single-use token from the URL query params session[:token] = client.auth_handler.upgrade() client.authsub_token = session[:token] if session[:token]
O tmp seguro é muito semelhante. A única adição é definindo sua chave privada antes de fazer upgrade do token:
PRIVATE_KEY = '/path/to/private_key.pem' client.authsub_token = params[:token] client.authsub_private_key = PRIVATE_KEY session[:token] = client.auth_handler.upgrade() client.authsub_token = session[:token] if session[:token]
Observação: para usar tokens seguros, defina secure=true
ao solicitar um
token de uso único. Consulte Como gerar o URL tmpRequest acima.
Gerenciamento de tokens
Há dois gerenciadores adicionais disponíveis para o gerenciamento de tokens, tmpTokenInfo e tmpRevogarToken. AuthSubTokenInfo
é útil para verificar
a validade de um token. O AuthSubRevokeToken
oferece aos usuários a opção de interromper o acesso aos dados. O app precisa usar AuthSubRevokeToken
como prática recomendada. Ambos os métodos são aceitos na biblioteca Ruby.
Para consultar os metadados de um token:
client.auth_handler.info
Para revogar um token de sessão:
client.auth_handler.revoke
Consulte a documentação completa do Authentication Autenticador para aplicativos da Web para saber mais sobre.
OAuth
No momento em que este artigo foi escrito, o OAuth não era adicionado ao módulo GData::Auth
.
O uso do OAuth na biblioteca de utilitários deve ser relativamente simples ao usar o plug-in oauth-plugin (link em inglês) ou a gem oauth do Ruby. Em ambos os casos, crie um objeto GData::HTTP::Request
e transmita a ele o cabeçalho Authorization
gerado por cada biblioteca.
Como acessar feeds
GET (busca de dados)
Depois de configurar um objeto cliente, use o método get()
para consultar um feed de dados do Google. O XPath pode ser usado para
recuperar elementos Atom específicos. Veja um exemplo de recuperação dos Documentos Google de um usuário:
feed = client.get('http://docs.google.com/feeds/documents/private/full').to_xml feed.elements.each('entry') do |entry| puts 'title: ' + entry.elements['title'].text puts 'type: ' + entry.elements['category'].attribute('label').value puts 'updated: ' + entry.elements['updated'].text puts 'id: ' + entry.elements['id'].text # Extract the href value from each <atom:link> links = {} entry.elements.each('link') do |link| links[link.attribute('rel').value] = link.attribute('href').value end puts links.to_s end
POST (criação de novos dados)
Use o método post()
de um cliente para criar novos dados no servidor. O exemplo a seguir adicionará
new_writer@example.com
como colaborador do documento com o ID: doc_id
.
# Return documents the authenticated user owns feed = client.get('http://docs.google.com/feeds/documents/private/full/-/mine').to_xml entry = feed.elements['entry'] # first <atom:entry> acl_entry = <<-EOF <entry xmlns="http://www.w3.org/2005/Atom" xmlns:gAcl='http://schemas.google.com/acl/2007'> <category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/acl/2007#accessRule'/> <gAcl:role value='writer'/> <gAcl:scope type='user' value='new_writer@example.com'/> </entry> EOF # Regex the document id out from the full <atom:id>. # http://docs.google.com/feeds/documents/private/full/document%3Adfrk14g25fdsdwf -> document%3Adfrk14g25fdsdwf doc_id = entry.elements['id'].text[/full\/(.*%3[aA].*)$/, 1] response = client.post("http://docs.google.com/feeds/acl/private/full/#{doc_id}", acl_entry)
PUT (atualização de dados)
Para atualizar dados no servidor, use o método put()
de um cliente. O exemplo a seguir atualiza o título de um documento.
Você precisa ter um feed de uma consulta anterior.
entry = feed.elements['entry'] # first <atom:entry> # Update the document's title entry.elements['title'].text = 'Updated title' entry.add_namespace('http://www.w3.org/2005/Atom') entry.add_namespace('gd','http://schemas.google.com/g/2005') edit_uri = entry.elements["link[@rel='edit']"].attributes['href'] response = client.put(edit_uri, entry.to_s)
EXCLUIR
Para excluir um <atom:Entry> ou outros dados do servidor, use o método delete()
.
O exemplo a seguir excluirá um documento. O código pressupõe que você tenha uma entrada de documento
de uma consulta anterior.
entry = feed.elements['entry'] # first <atom:entry> edit_uri = entry.elements["link[@rel='edit']"].attributes['href'] client.headers['If-Match'] = entry.attribute('etag').value # make sure we don't nuke another client's updates client.delete(edit_uri)
Como criar um novo aplicativo do Rail
Normalmente, o primeiro exercício na criação de um novo aplicativo do Beam envolve a execução de geradores de scaffold para criar os arquivos MVC.
Depois disso, ele está executando rake db:migrate
para configurar as tabelas do banco de dados. No entanto, como nosso aplicativo consultará a API Google Documents
List para dados, precisamos de uma estrutura ou banco de dados genérico. Em vez disso, crie um novo aplicativo e um controlador simples:
rails doclist cd doclist ruby script/generate controller doclist
e fazer as seguintes mudanças em config/environment.rb
:
config.frameworks -= [ :active_record, :active_resource, :action_mailer ] config.gem 'gdata', :lib => 'gdata'
A primeira linha desvincula ActiveRecord
do aplicativo.
A segunda linha carrega a gem gdata
na inicialização.
Por fim, escolhi conectar a rota padrão ("/
") à ação documents
em DoclistController
.
Adicione esta linha a config/routes.rb
:
map.root :controller => 'doclist', :action => 'all'
Iniciar um controlador
Como não geramos andaimes, adicione manualmente uma ação chamada "all
" ao
DoclistController
no app/controllers/doclist_controller.rb
.
class DoclistController < ApplicationController def all @foo = 'I pity the foo!' end end
e crie all.html.erb
em app/views/doclist/
:
<%= @foo %>
Ativar o servidor da Web e iniciar o desenvolvimento
Agora você poderá iniciar o servidor da Web padrão invocando ruby script/server
.
Se tudo estiver certo, apontar o navegador para http://localhost:3000/
vai exibir "I pity the foo!
".
Dica: não se esqueça de remover ou renomear public/index.html
.
Quando tudo estiver funcionando, dê uma olhada nos finais
DoclistController
e
ApplicationController
da carne
do projeto DocList Manager. Você também pode analisar
ContactsController
, que
processa as chamadas para a API Google Contacts.
Conclusão
A parte mais difícil da criação de um aplicativo do Google Data Rail é configurar o! No entanto, um segundo próximo é implantar o aplicativo. Para isso, é altamente recomendável usar mod_rails para o Apache. É muito fácil de configurar, instalar e executar. Tudo estará pronto em breve.
Recursos
- Lista de APIs de dados do Google
- Página do projeto Biblioteca de utilitários do Google Data Ruby
- Artigo: Como usar o Ruby com as APIs de dados do Google
- Fazer o download do Ruby
- Fazer o download do RubyGems e do Rail
Apêndice
Exemplos
O DocList Manager é uma amostra completa do Ruby on Rail que demonstra os tópicos discutidos neste artigo. O código-fonte completo está disponível na hospedagem do projeto.