Google Data on Rails

에릭 비델만, Google 데이터 API팀
2009년 2월

소개

'클라이언트 라이브러리 목록에 Ruby가 어디에 있어?'

개발자의 엄청난 수요와 Ruby on Rails (RoR)의 지속적인 인기에 힘입어 동료인 Jeff Fisher가 파멸의 산의 뜨거운 심연에서 Ruby 유틸리티 라이브러리를 만들었습니다. 완전한 클라이언트 라이브러리는 아니지만 인증 및 기본 XML 조작과 같은 기본 사항을 처리합니다. 또한 REXML 모듈과 XPath를 사용하여 Atom 피드를 직접 작업해야 합니다.

잠재고객

이 도움말은 Ruby, 특히 Ruby on Rails를 사용하여 Google Data API에 액세스하는 데 관심이 있는 개발자를 대상으로 합니다. 이 가이드는 독자가 Ruby 프로그래밍 언어와 Rails 웹 개발 프레임워크에 어느 정도 익숙하다고 가정합니다. 대부분의 샘플에서는 문서 목록 API에 중점을 두지만 동일한 개념을 데이터 API에 적용할 수 있습니다.

시작하기

요구사항

Google Data Ruby 유틸리티 라이브러리 설치

라이브러리를 가져오려면 프로젝트 호스팅에서 직접 라이브러리 소스를 다운로드하거나 gem을 설치하면 됩니다.

sudo gem install gdata

: 만약을 대비하여 gem list --local를 실행하여 gem이 올바르게 설치되었는지 확인합니다.

인증

ClientLogin

ClientLogin을 사용하면 애플리케이션에서 사용자를 Google 또는 G Suite 계정에 프로그래매틱 방식으로 로그인시킬 수 있습니다. 사용자의 사용자 인증 정보를 검증하면 Google에서 후속 API 요청에서 참조할 인증 토큰을 발급합니다. 토큰은 사용 중인 Google 서비스에 의해 정의된 설정된 기간 동안 유효합니다. 보안상의 이유와 사용자에게 최상의 환경을 제공하기 위해 설치된 데스크톱 애플리케이션을 개발할 때만 ClientLogin을 사용해야 합니다. 웹 애플리케이션의 경우 AuthSub 또는 OAuth를 사용하는 것이 좋습니다.

Ruby 라이브러리에는 각 API의 클라이언트 클래스가 있습니다. 예를 들어 다음 코드 스니펫을 사용하여 user@gmail.com을 Documents List Data 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)

참고: 기본적으로 라이브러리는 accountTypeHOSTED_OR_GOOGLE를 사용합니다. 가능한 값은 HOSTED_OR_GOOGLE, HOSTED 또는 GOOGLE입니다.

ClientLogin 사용의 단점 중 하나는 로그인 시도가 실패할 때 애플리케이션에 보안문자 챌린지가 전송될 수 있다는 것입니다. 이 경우 client.clientlogin(username, password, captcha_token, captcha_answer) 추가 매개변수를 사용하여 clientlogin() 메서드를 호출하여 오류를 처리할 수 있습니다. CAPTCHA 처리에 관한 자세한 내용은 전체 설치된 애플리케이션 인증 문서를 참고하세요.

AuthSub

AuthSubRequest URL 생성

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)

이전 코드 블록은 authsub_link에 다음 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

클라이언트 객체의 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를 설정해야 합니다. 위의 AuthSubRequest URL 생성을 참고하세요.

토큰 관리

AuthSub는 토큰 관리를 위해 두 가지 추가 핸들러인 AuthSubTokenInfoAuthSubRevokeToken을 제공합니다. AuthSubTokenInfo은 토큰의 유효성을 확인하는 데 유용합니다. AuthSubRevokeToken를 사용하면 사용자가 데이터 액세스를 중단할 수 있습니다. 앱은 AuthSubRevokeToken을 권장사항으로 사용해야 합니다. 두 메서드 모두 Ruby 라이브러리에서 지원됩니다.

토큰의 메타데이터를 쿼리하려면 다음 단계를 따르세요.

client.auth_handler.info

세션 토큰을 취소하려면 다음을 사용하세요.

client.auth_handler.revoke

AuthSub에 관한 자세한 내용은 전체 웹 애플리케이션용 AuthSub 인증 문서를 참고하세요.

OAuth

이 도움말을 작성하는 시점에는 OAuth가 GData::Auth 모듈에 추가되지 않았습니다.

Rails oauth-plugin 또는 Ruby oauth gem을 사용하는 경우 유틸리티 라이브러리에서 OAuth를 사용하는 것은 비교적 간단합니다. 어떤 경우든 GData::HTTP::Request 객체를 만들고 각 라이브러리에서 생성된 Authorization 헤더를 전달해야 합니다.

피드 액세스

GET (데이터 가져오기)

클라이언트 객체를 설정한 후에는 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() 메서드를 사용하여 서버에 새 데이터를 만듭니다. 다음 예시에서는 ID가 doc_id인 문서에 new_writer@example.com를 공동작업자로 추가합니다.

# 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를 실행하여 데이터베이스 테이블을 설정합니다. 하지만 애플리케이션이 Google 문서 목록 API에서 데이터를 쿼리하므로 일반적인 스캐폴딩이나 데이터베이스는 거의 필요하지 않습니다. 대신 새 애플리케이션과 간단한 컨트롤러를 만듭니다.

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 gem을 로드합니다.

마지막으로 기본 경로 ('/')를 DoclistControllerdocuments 작업에 연결했습니다. config/routes.rb에 다음 줄을 추가합니다.

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

컨트롤러 시작

스캐폴딩을 생성하지 않았으므로 app/controllers/doclist_controller.rbDoclistController에 'all'라는 작업을 수동으로 추가합니다.

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

app/views/doclist/ 아래에 all.html.erb를 만듭니다.

<%= @foo %>

웹 서버를 실행하고 개발 시작

이제 ruby script/server를 호출하여 기본 웹 서버를 시작할 수 있습니다. 모든 것이 정상이라면 브라우저를 http://localhost:3000/로 지정하면 'I pity the foo!'이 표시됩니다.

도움말: public/index.html를 삭제하거나 이름을 변경해야 합니다.

작업이 완료되면 최종 DoclistControllerApplicationController을 확인하여 DocList Manager 프로젝트의 핵심을 살펴보세요. Google 주소록 API 호출을 처리하는 ContactsController도 확인하세요.

결론

Google Data Rails 앱을 만들 때 가장 어려운 부분은 Rails를 구성하는 것입니다. 하지만 애플리케이션을 배포하는 것도 이에 못지않게 중요합니다. 이를 위해 Apache의 mod_rails를 적극 권장합니다. 설정, 설치, 실행이 매우 쉽습니다. 금방 시작할 수 있습니다.

리소스

부록

DocList Manager는 이 도움말에서 설명하는 주제를 보여주는 완전한 Ruby on Rails 샘플입니다. 전체 소스 코드는 프로젝트 호스팅에서 확인할 수 있습니다.