Февраль 2009 г.
Введение
«Где Ruby в списке клиентских библиотек ?»
Вдохновленный неуемным аппетитом наших разработчиков и непреходящей популярностью Ruby on Rails (RoR), мой коллега Джефф Фишер создал библиотеку утилит Ruby из огненных глубин горы Рока. Обратите внимание, что это не полноценная клиентская библиотека, но она реализует такие фундаментальные функции, как аутентификация и базовые операции с XML. Кроме того, она требует прямой работы с Atom-каналом, используя модуль REXML и XPath.
Аудитория
Эта статья предназначена для разработчиков, заинтересованных в доступе к API Google Data с помощью Ruby, в частности, Ruby on Rails. Предполагается, что читатель имеет некоторое представление о языке программирования Ruby и фреймворке веб-разработки Rails. В большинстве примеров я остановлюсь на API списка документов , но те же принципы применимы к любому API данных .
Начиная
Требования
Установка библиотеки утилит Google Data Ruby
Чтобы получить библиотеку, вы можете либо загрузить исходный код библиотеки непосредственно с хостинга проекта, либо установить gem:
sudo gem install gdata
Совет : для верности выполните команду gem list --local
чтобы убедиться, что пакет установлен правильно.
Аутентификация
ClientLogin
ClientLogin позволяет вашему приложению программно авторизовать пользователей в их учётных записях Google или G Suite. После проверки учётных данных пользователя Google выдаёт токен авторизации, который будет использоваться в последующих запросах API. Токен остаётся действительным в течение определённого времени, определяемого используемым сервисом Google. В целях безопасности и для обеспечения максимального удобства пользователей следует использовать ClientLogin только при разработке устанавливаемых десктопных приложений. Для веб-приложений предпочтительнее использовать AuthSub или OAuth .
В библиотеке Ruby есть клиентский класс для каждого из API. Например, используйте следующий фрагмент кода для входа в API данных списка документов по user@gmail.com
:
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 см. в полной документации по аутентификации для установленных приложений .
AuthSub
Генерация 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]
Secure 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 для веб-приложений см. в полной версии.
OAuth
На момент написания статьи OAuth не был добавлен в модуль GData::Auth
.
Использование OAuth в библиотеке утилит должно быть относительно простым при использовании плагина Rails oauth-plugin или гема Ruby oauth . В любом случае вам потребуется создать объект GData::HTTP::Request
и передать ему заголовок Authorization
, сгенерированный каждой библиотекой.
Доступ к лентам
GET (извлечение данных)
После настройки объекта клиента используйте его метод get()
для запроса к фиду Google Data. XPath можно использовать для извлечения определённых элементов Atom. Вот пример извлечения данных из Google Documents пользователя:
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 Contacts.
Заключение
Самая сложная часть создания приложения Google Data Rails — это настройка Rails! Однако, на втором месте стоит развёртывание приложения. Для этого я настоятельно рекомендую mod_rails для Apache. Он невероятно прост в настройке, установке и запуске. Вы сможете начать работу в кратчайшие сроки!
Ресурсы
- Список API данных Google
- Страница проекта библиотеки утилит Google Data Ruby
- Статья: Использование Ruby с API Google Data
- Скачать Руби
- Загрузите RubyGems и Rails
Приложение
Примеры
DocList Manager — это полноценный пример Ruby on Rails, демонстрирующий темы, обсуждаемые в этой статье. Полный исходный код доступен на хостинге проекта.