fevereiro de 2009
Introdução
"Onde está o Ruby na lista de bibliotecas de cliente?"
Motivado pelo apetite voraz dos nossos desenvolvedores e pela popularidade duradoura do Ruby on Rails (RoR), meu colega Jeff Fisher criou uma biblioteca de utilitários do Ruby nas profundezas do Monte Doom. Não é uma biblioteca de cliente completa, mas processa os fundamentos, 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 XPath.
Público-alvo
Este artigo é destinado a desenvolvedores interessados em acessar as APIs de dados do Google usando Ruby, especificamente Ruby on Rails. Ele pressupõe que o leitor tem alguma familiaridade com a linguagem de programação Ruby e o framework de desenvolvimento da Web Rails. A maioria dos exemplos se concentra na API Documents List, mas os mesmos conceitos podem ser aplicados a qualquer uma das APIs de dados.
Primeiros passos
Requisitos
- Download do patch level 114+ do Ruby 1.8.6
- Faça o download do RubyGems 1.3.1 ou mais recente.
- Rails 2.2.2+ download
Como instalar a biblioteca de utilitários do Google Data Ruby
Para conseguir a biblioteca, faça o download da fonte da biblioteca diretamente da hospedagem do projeto ou instale a gem:
sudo gem install gdata
Dica: para garantir, execute gem list --local
e verifique se a gem foi instalada corretamente.
Autenticação
ClientLogin
O ClientLogin permite que seu aplicativo faça login programaticamente nas contas do Google ou do G Suite dos usuários. Ao validar as credenciais do usuário, o Google emite um token de autenticação para ser referenciado em solicitações de API subsequentes. O token permanece válido por um período de tempo definido pelo serviço do Google que você está usando. Por motivos de segurança e para oferecer a melhor experiência aos usuários, use o ClientLogin apenas ao desenvolver aplicativos instalados para computador. Para aplicativos da Web, é preferível usar o AuthSub ou o OAuth.
A biblioteca Ruby tem uma classe de cliente para cada uma das APIs. Por exemplo, use o snippet de código a seguir para fazer login em user@gmail.com
na
API Data de lista de documentos:
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')
Confira 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 o 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 testes de CAPTCHA em tentativas de login com falha. Se isso acontecer,
chame o método clientlogin()
com os parâmetros adicionais: client.clientlogin(username, password, captcha_token, captcha_answer)
. Consulte a documentação completa sobre Autenticação para aplicativos instalados para mais informações sobre como lidar com CAPTCHAs.
AuthSub
Como gerar o URL AuthSubRequest
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 tem um atributo authsub_scope
padrão definido, 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 seguinte URL:
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
Fazer upgrade de um token de uso único para um token de sessão
O AuthSub vai redirecionar o usuário de volta para http://example.com/change/to/your/app?token=SINGLE_USE_TOKEN
depois que ele conceder acesso aos dados. O URL é apenas 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 AuthSub seguro é muito parecido. A única adição é definir 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 AuthSubRequest acima.
Gerenciamento de tokens
O AuthSub oferece dois manipuladores extras, AuthSubTokenInfo e
AuthSubRevokeToken, para gerenciar tokens. AuthSubTokenInfo
é útil para verificar
a validade de um token. O AuthSubRevokeToken
oferece aos usuários a opção de descontinuar o acesso aos dados deles. Seu app precisa usar AuthSubRevokeToken
como prática recomendada. Os dois métodos são compatíveis com a 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 sobre a autenticação AuthSub para aplicativos da Web.
OAuth
No momento em que este artigo foi escrito, o OAuth ainda não havia sido adicionado ao módulo GData::Auth
.
Usar o OAuth na biblioteca de utilitários é relativamente simples ao usar o oauth-plugin do Rails ou a
gem oauth do Ruby. Em ambos os casos, crie um objeto GData::HTTP::Request
e transmita 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()
dele para consultar um feed de dados do Google. O XPath pode ser usado para
recuperar elementos Atom específicos. Confira um exemplo de como recuperar os documentos do 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 adiciona
new_writer@example.com
como colaborador ao 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.
Ele pressupõe que você tem 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 exclui um documento. O código pressupõe que você tem 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 Rails
Normalmente, o primeiro exercício na criação de um novo app Rails envolve a execução dos geradores de scaffold para criar seus arquivos MVC.
Depois disso, ele executa rake db:migrate
para configurar as tabelas do banco de dados. No entanto, como nosso aplicativo vai consultar a API Google Documents List
para dados, não precisamos de scaffolding ou bancos de dados genéricos. Em vez disso, crie um novo aplicativo e um controlador simples:
rails doclist cd doclist ruby script/generate controller doclist
e faça 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 gema 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 scaffolding, adicione manualmente uma ação chamada "all
" ao
DoclistController
em 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 %>
Iniciar o servidor da Web e o desenvolvimento
Agora você pode iniciar o servidor da Web padrão invocando ruby script/server
.
Se tudo estiver certo, ao apontar o navegador para http://localhost:3000/
, a mensagem "I pity the foo!
" vai aparecer.
Dica: não se esqueça de remover ou renomear public/index.html
.
Depois que tudo estiver funcionando, confira meu
DoclistController
e
ApplicationController
finais para o conteúdo
do projeto DocList Manager. Também é recomendável consultar
ContactsController
, que
processa as chamadas para a API Google Contacts.
Conclusão
A parte mais difícil de criar um app do Google Data Rails é configurar o Rails. No entanto, a segunda opção mais importante é implantar o aplicativo. Para isso, recomendo o mod_rails para o Apache. É muito fácil de configurar, instalar e executar. Em pouco tempo, tudo estará pronto para começar.
Recursos
- Lista de APIs de dados do Google
- Página do projeto Biblioteca de utilitários do Google Data Ruby
- Artigo: Como usar Ruby com as APIs Google Data
- Baixar o Ruby
- Fazer o download do RubyGems e do Rails
Apêndice
Exemplos
O DocList Manager é uma amostra completa do Ruby on Rails que demonstra os tópicos discutidos neste artigo. O código-fonte completo está disponível na hospedagem do projeto.