Dane Google w Rails

Eric Bidelman, zespół interfejsów API danych Google
Luty 2009 r.

Wprowadzenie

„Gdzie na liście bibliotek klienta jest Ruby?”

Zainspirowany ogromnym zainteresowaniem naszych programistów i nieustającą popularnością Ruby on Rails (RoR) mój kolega Jeff Fisher stworzył bibliotekę narzędzi Ruby z ognistych głębin Góry Przeznaczenia. Nie jest to pełna biblioteka klienta, ale obsługuje podstawowe funkcje, takie jak uwierzytelnianie i podstawowa manipulacja plikami XML. Wymaga to też bezpośredniej pracy z kanałem Atom za pomocą modułu REXML i XPath.

Odbiorcy

Ten artykuł jest przeznaczony dla deweloperów, którzy chcą uzyskać dostęp do interfejsów Google Data API za pomocą języka Ruby, a w szczególności Ruby on Rails. Zakładamy, że czytelnik ma pewną znajomość języka programowania Ruby i platformy Rails do tworzenia aplikacji internetowych. Większość przykładów dotyczy interfejsu Documents List API, ale te same koncepcje można zastosować do dowolnego interfejsu Data API.

Pierwsze kroki

Wymagania

  • Ruby 1.8.6, poziom poprawki 114 lub nowszy pobierz
  • RubyGems 1.3.1 lub nowsza pobierz
  • Rails 2.2.2+ pobierz

Instalowanie biblioteki narzędzi Google Data Ruby

Aby uzyskać bibliotekę, możesz pobrać źródło biblioteki bezpośrednio z hostingu projektu lub zainstalować gem:

sudo gem install gdata

Wskazówka: dla pewności uruchom polecenie gem list --local, aby sprawdzić, czy gem został prawidłowo zainstalowany.

Uwierzytelnianie

ClientLogin

ClientLogin umożliwia aplikacji programowe logowanie użytkowników na ich konta Google lub G Suite. Po zweryfikowaniu danych logowania użytkownika Google wydaje token uwierzytelniania, do którego można się odwoływać w kolejnych żądaniach interfejsu API. Token pozostaje ważny przez określony czas, który zależy od usługi Google, z której korzystasz. Ze względów bezpieczeństwa i aby zapewnić użytkownikom jak najlepsze wrażenia, interfejsu ClientLogin należy używać tylko podczas tworzenia zainstalowanych aplikacji na komputery. W przypadku aplikacji internetowych zalecamy używanie AuthSub lub OAuth.

Biblioteka Ruby zawiera klasę klienta dla każdego interfejsu API. Aby na przykład zalogować się w interfejsie Documents List Data API, użyj tego fragmentu kodu: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')

Zobacz pełną listę wdrożonych klas usług. Jeśli usługa nie ma klasy klienta, użyj klasy GData::Client::Base. Na przykład poniższy kod wymusza logowanie się użytkowników za pomocą konta 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)

Uwaga: domyślnie biblioteka używa HOSTED_OR_GOOGLE dla accountType. Możliwe wartości to HOSTED_OR_GOOGLE, HOSTED lub GOOGLE.

Jedną z wad korzystania z ClientLogin jest to, że w przypadku nieudanych prób logowania aplikacja może otrzymywać testy CAPTCHA. W takim przypadku możesz obsłużyć błąd, wywołując metodę clientlogin() z dodatkowymi parametrami:client.clientlogin(username, password, captcha_token, captcha_answer). Więcej informacji o rozwiązywaniu testów CAPTCHA znajdziesz w pełnej dokumentacji Uwierzytelnianie w przypadku aplikacji zainstalowanych.

AuthSub

Generowanie adresu 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)

Poprzedni blok kodu tworzy w authsub_link ten adres URL:

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

Możesz też użyć metody authsub_url obiektu klienta. Każda klasa usług ma ustawiony domyślny atrybut authsub_scope, więc nie musisz określać własnego.

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)

Poprzedni blok kodu tworzy ten adres 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

Przekształcanie tokena jednorazowego w token sesji

AuthSub przekieruje użytkownika z powrotem do http://example.com/change/to/your/app?token=SINGLE_USE_TOKEN, gdy przyzna on dostęp do swoich danych. Zwróć uwagę, że adres URL to po prostu nasz adres next_url z dołączonym jednorazowym tokenem jako parametrem zapytania.

Następnie wymień token jednorazowy na token sesji o długim okresie ważności:

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]

Bezpieczna autoryzacja AuthSub działa bardzo podobnie. Jedyną zmianą jest ustawienie klucza prywatnego przed uaktualnieniem tokena:

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]

Uwaga: aby używać bezpiecznych tokenów, podczas wysyłania prośby o token jednorazowy ustaw wartość secure=true. Zobacz Generowanie adresu URL AuthSubRequest powyżej.

Zarządzanie tokenami

AuthSub udostępnia 2 dodatkowe moduły obsługi: AuthSubTokenInfoAuthSubRevokeToken, które służą do zarządzania tokenami. AuthSubTokenInfo przydaje się do sprawdzania ważności tokena. AuthSubRevokeToken daje użytkownikom możliwość przerwania dostępu do ich danych. Zgodnie ze sprawdzonymi metodami aplikacja powinna używać AuthSubRevokeToken. Obie metody są obsługiwane w bibliotece Ruby.

Aby wysłać zapytanie dotyczące metadanych tokena:

client.auth_handler.info

Aby cofnąć token sesji:

client.auth_handler.revoke

Pełne informacje o AuthSub znajdziesz w dokumentacji Uwierzytelnianie AuthSub w aplikacjach internetowych.

OAuth

W momencie pisania tego artykułu autoryzacja OAuth nie została jeszcze dodana do modułu GData::Auth.

Korzystanie z OAuth w bibliotece narzędziowej powinno być stosunkowo proste, jeśli używasz wtyczki oauth Rails lub gemu oauth Ruby. W obu przypadkach musisz utworzyć obiekt GData::HTTP::Request i przekazać mu nagłówek Authorization wygenerowany przez każdą bibliotekę.

Dostęp do plików danych

GET (pobieranie danych)

Po skonfigurowaniu obiektu klienta użyj jego metody get(), aby wysłać zapytanie do pliku danych Google. Za pomocą XPath możesz pobierać konkretne elementy Atom. Oto przykład pobierania dokumentów Google użytkownika:

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 (tworzenie nowych danych)

Użyj metody post() klienta, aby utworzyć nowe dane na serwerze. W tym przykładzie dodamy użytkownika new_writer@example.com jako współpracownika dokumentu o identyfikatorze 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 (aktualizacja danych)

Aby zaktualizować dane na serwerze, użyj metody put() klienta. Poniższy przykład pokazuje, jak zaktualizować tytuł dokumentu. Zakładamy, że masz plik danych z poprzedniego zapytania.

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)

USUŃ

Aby usunąć z serwera element <atom:entry> lub inne dane, użyj metody delete(). W tym przykładzie usuniemy dokument. Zakładamy, że masz wpis dokumentu z poprzedniego zapytania.

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)

Tworzenie nowej aplikacji Rails

Zwykle pierwszym ćwiczeniem podczas tworzenia nowej aplikacji Rails jest uruchomienie generatorów szkieletów w celu utworzenia plików MVC. Następnie uruchamia się rake db:migrate, aby skonfigurować tabele bazy danych. Ponieważ jednak nasza aplikacja będzie wysyłać zapytania do interfejsu Google Documents List API w celu uzyskania danych, nie potrzebujemy ogólnych szkieletów ani baz danych. Zamiast tego utwórz nową aplikację i prosty kontroler:

rails doclist
cd doclist
ruby script/generate controller doclist

i wprowadź te zmiany w config/environment.rb:

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

Pierwsza linia odłącza ActiveRecord od aplikacji. Drugi wiersz wczytuje klejnot gdata podczas uruchamiania.

Na koniec połączyłem domyślną ścieżkę („/”) z działaniem documentsDoclistController. Dodaj ten wiersz do pliku config/routes.rb:

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

Uruchamianie kontrolera

Nie wygenerowaliśmy szkieletu, więc ręcznie dodaj działanie o nazwie „all” do DoclistControllerapp/controllers/doclist_controller.rb.

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

i utwórz all.html.erb w sekcji app/views/doclist/:

<%= @foo %>

Uruchom serwer WWW i rozpocznij programowanie

Teraz możesz uruchomić domyślny serwer WWW, wywołując polecenie ruby script/server. Jeśli wszystko jest w porządku, po otwarciu w przeglądarce adresu http://localhost:3000/ powinien wyświetlić się tekst „I pity the foo!”.

Wskazówka: nie zapomnij usunąć lub zmienić nazwy public/index.html.

Gdy wszystko będzie działać, zapoznaj się z moimi ostatecznymi wersjami DoclistControllerApplicationController, aby poznać najważniejsze elementy projektu DocList Manager. Warto też przyjrzeć się plikowi ContactsController, który obsługuje wywołania interfejsu Google Contacts API.

Podsumowanie

Najtrudniejszą częścią tworzenia aplikacji Google Data Rails jest skonfigurowanie Rails. Drugim najważniejszym krokiem jest wdrożenie aplikacji. W tym celu zdecydowanie polecam mod_rails dla Apache. Jest bardzo łatwy w konfiguracji, instalacji i uruchomieniu. Zaczniesz korzystać z usługi w mgnieniu oka.

Zasoby

Dodatek

Przykłady

DocList Manager to pełny przykład w Ruby on Rails, który ilustruje tematy omówione w tym artykule. Pełny kod źródłowy jest dostępny w hostingu projektu.