Данные Google на Rails

Эрик Бидельман, команда API данных Google
февраль 2009 г.

Введение

«Где Ruby в списке клиентских библиотек

Вдохновленный неистовым аппетитом наших разработчиков и непреходящей популярностью Ruby on Rails (RoR), мой коллега Джефф Фишер выковал библиотеку утилит Ruby из огненных недр Mount Doom. Имейте в виду, что это не полноценная клиентская библиотека, но она поддерживает такие основы, как аутентификация и базовые операции с XML. Также требуется, чтобы вы работали напрямую с каналом Atom, используя модуль REXML и XPath.

Аудитория

Эта статья предназначена для разработчиков, заинтересованных в доступе к API данных Google с помощью Ruby, в частности Ruby on Rails. Предполагается, что читатель немного знаком с языком программирования Ruby и средой веб-разработки Rails. Я сосредоточился на API списка документов для большинства примеров, но те же самые концепции могут быть применены к любому из API данных .

Начиная

Требования

Установка служебной библиотеки Google Data Ruby

Чтобы получить библиотеку, вы можете либо загрузить исходный код библиотеки непосредственно с хостинга проекта, либо установить гем:

sudo gem install gdata

Совет : На всякий случай запустите gem list --local , чтобы убедиться, что гем установлен правильно.

Аутентификация

КлиентЛогин

ClientLogin позволяет вашему приложению программно входить пользователей в их учетную запись Google или G Suite. После проверки учетных данных пользователя Google выдает токен аутентификации, на который будут ссылаться в последующих запросах API. Токен остается действительным в течение установленного периода времени, определяемого сервисом Google, с которым вы работаете. Из соображений безопасности и для обеспечения наилучшего взаимодействия с пользователями вам следует использовать ClientLogin только при разработке установленных настольных приложений. Для веб-приложений предпочтительнее использовать AuthSub или OAuth .

В библиотеке Ruby есть клиентский класс для каждого API. Например, используйте следующий фрагмент кода для входа user@gmail.com в API данных списка документов:

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

См. полный список реализованных классов обслуживания . Если у службы нет клиентского класса, используйте класс GData::Client::Base . Например, следующий код заставляет пользователей входить в систему с учетной записью 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)

Примечание . По умолчанию библиотека использует HOSTED_OR_GOOGLE для accountType . Возможные значения: HOSTED_OR_GOOGLE , HOSTED или GOOGLE .

Одним из недостатков использования ClientLogin является то, что вашему приложению могут быть отправлены запросы CAPTCHA при неудачных попытках входа в систему. В этом случае вы можете обработать ошибку, вызвав метод clientlogin() с его дополнительными параметрами: client.clientlogin(username, password, captcha_token, captcha_answer) . Обратитесь к полной документации по аутентификации для установленных приложений для получения дополнительной информации о работе с CAPTCHA.

Аутсуб

Создание 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)

Предыдущий блок кода создает следующий URL-адрес в 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

Вы также можете использовать метод authsub_url клиентского объекта. Для каждого класса обслуживания задан атрибут authsub_scope по умолчанию, поэтому нет необходимости указывать свой собственный.

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)

Предыдущий блок кода создает следующий 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

Обновление одноразового токена до токена сеанса

AuthSub перенаправит пользователя обратно на http://example.com/change/to/your/app?token=SINGLE_USE_TOKEN , как только он предоставит доступ к своим данным. Обратите внимание, что URL — это просто наш next_url с одноразовым токеном, добавленным в качестве параметра запроса.

Затем замените одноразовый токен на долгоживущий токен сеанса:

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]

Безопасный AuthSub очень похож. Единственное дополнение — установить закрытый ключ перед обновлением токена:

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]

Примечание . Чтобы использовать защищенные токены, обязательно установите secure=true при запросе одноразового токена. См. раздел Создание URL-адреса AuthSubRequest выше.

Управление токенами

AuthSub предоставляет два дополнительных обработчика, AuthSubTokenInfo и AuthSubRevokeToken для управления токенами. AuthSubTokenInfo полезен для проверки действительности токена. AuthSubRevokeToken дает пользователям возможность прекратить доступ к своим данным. В вашем приложении рекомендуется использовать AuthSubRevokeToken . Оба метода поддерживаются в библиотеке Ruby.

Чтобы запросить метаданные токена:

client.auth_handler.info

Чтобы отозвать токен сеанса:

client.auth_handler.revoke

Полную информацию об AuthSub см. в полной документации по аутентификации AuthSub для веб-приложений .

OAuth

На момент написания этой статьи OAuth еще не был добавлен в модуль GData::Auth .

Использование OAuth в служебной библиотеке должно быть относительно простым при использовании Rails oauth-plugin или Ruby oauth gem . В любом случае вам нужно создать объект GData::HTTP::Request и передать ему заголовок Authorization , сгенерированный каждой библиотекой.

Доступ к фидам

ПОЛУЧИТЬ (извлечение данных)

После того как вы настроили клиентский объект, используйте его метод get() для запроса фида данных Google. XPath можно использовать для извлечения определенных элементов Atom. Вот пример получения документов Google пользователя:

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 (создание новых данных)

Используйте клиентский метод post() для создания новых данных на сервере. Следующий пример добавит new_writer@example.com в качестве соавтора к документу с идентификатором: 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 (обновление данных)

Чтобы обновить данные на сервере, используйте клиентский метод put() . В следующем примере будет обновлен заголовок документа. Предполагается, что у вас есть фид из предыдущего запроса.

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)

УДАЛИТЬ

Чтобы удалить <atom:entry> или другие данные с сервера, используйте метод delete() . В следующем примере будет удален документ. Код предполагает, что у вас есть запись документа из предыдущего запроса.

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)

Создание нового приложения Rails

Обычно первое упражнение по созданию нового приложения Rails включает в себя запуск генераторов шаблонов для создания файлов MVC. После этого он запускает rake db:migrate для настройки таблиц вашей базы данных. Однако, поскольку наше приложение будет запрашивать данные у API-интерфейса Google Documents List, нам не нужны общие шаблоны или базы данных. Вместо этого создайте новое приложение и простой контроллер:

rails doclist
cd doclist
ruby script/generate controller doclist

и внесите следующие изменения в config/environment.rb :

config.frameworks -= [ :active_record, :active_resource, :action_mailer ]
config.gem 'gdata', :lib => 'gdata'

Первая строка отключает ActiveRecord от приложения. Вторая строка загружает гем gdata при запуске.

Наконец, я решил подключить маршрут по умолчанию (' / ') к действию documents в DoclistController . Добавьте эту строку в config/routes.rb :

map.root :controller => 'doclist', :action => 'all'

Запустить контроллер

Поскольку мы не создавали скаффолдинг, вручную добавьте действие all в DoclistController в app/controllers/doclist_controller.rb .

class DoclistController < ApplicationController
  def all
    @foo = 'I pity the foo!'
  end
end

и создайте all.html.erb в app/views/doclist/ :

<%= @foo %>

Запустите веб-сервер и начните разработку

Теперь вы сможете запустить веб-сервер по умолчанию, вызвав ruby script/server . Если все в порядке, при указании в браузере адреса http://localhost:3000/ должно появиться сообщение « I pity the foo! '.

Совет . Не забудьте удалить или переименовать public/index.html .

Как только у вас все заработает, взгляните на мои последние DoclistController и ApplicationController , чтобы узнать суть проекта DocList Manager. Вы также захотите взглянуть на ContactsController , который обрабатывает вызовы API контактов Google.

Заключение

Самая сложная часть создания приложения Google Data Rails — это настройка Rails! Тем не менее, второе место занимает развертывание вашего приложения. Для этого я настоятельно рекомендую mod_rails для Apache. Его очень легко настроить, установить и запустить. Вы будете в рабочем состоянии в кратчайшие сроки!

Ресурсы

Приложение

Примеры

DocList Manager — это полный образец Ruby on Rails, демонстрирующий темы, обсуждаемые в этой статье. Полный исходный код доступен на хостинге проекта.