레일스에 대한 Google 데이터

Eric Bidelman, Google 데이터 API팀
2009년 2월

소개

"Ruby는 클라이언트 라이브러리 목록에서 어디에 있나요?"

동료 개발자인 제이피 피셔는 루비 온 레일(RoR)의 지속적인 인기에 힘입어 열정적인 깊이의 Ruby 유틸리티 라이브러리를 구축했습니다. 전체 클라이언트 라이브러리는 아니지만 인증 및 기본 XML 조작과 같은 기본 사항을 처리합니다. 또한 REXML 모듈 및 XPath를 사용하여 Atom 피드로 직접 작업해야 합니다.

대상

이 도움말은 Ruby를 사용해 Google Data API에 액세스하는 데 관심이 있는 개발자를 대상으로 합니다. 독자가 Ruby 프로그래밍 언어와 Rust 웹 개발 프레임워크를 잘 알고 있다고 가정합니다. 대부분의 샘플에서 Documents List API에 중점을 두지만 모든 Data API에 동일한 개념을 적용할 수 있습니다.

시작하기

요구사항

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

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

sudo gem install gdata

도움말: gem list --local을 실행하여 보석이 제대로 설치되었는지 확인하세요.

인증

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

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는 토큰 관리를 위한 두 가지 추가 핸들러, AuthSubTokenInfoAuthSubDismissToken을 제공합니다. AuthSubTokenInfo는 토큰의 유효성을 확인하는 데 유용합니다. AuthSubRevokeToken를 사용하면 사용자가 데이터 액세스를 중단할 수 있습니다. 앱에서는 권장사항으로 AuthSubRevokeToken를 사용해야 합니다. 두 가지 방법 모두 Ruby 라이브러리에서 지원됩니다.

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

client.auth_handler.info

세션 토큰을 취소하려면 다음 안내를 따르세요.

client.auth_handler.revoke

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

OAuth

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

유틸리티 라이브러리에서 OAuth를 사용하는 것은 과제 OAuth-plugin 또는 Ruby OAuth gem을 사용할 때 비교적 간단합니다. 두 경우 모두 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() 메서드를 사용하여 서버에 새 데이터를 만듭니다. 다음 예에서는 new_writer@example.com를 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 (데이터 업데이트)

서버의 데이터를 업데이트하려면 클라이언트의 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)

새 레일 애플리케이션 만들기

일반적으로 새 레일 앱을 만드는 첫 번째 연습에서는 Scaffold 생성기를 실행하여 MVC 파일을 만듭니다. 그런 다음 rake db:migrate를 실행하여 데이터베이스 테이블을 설정합니다. 하지만 애플리케이션에서 Google Documents List 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을 삭제하거나 이름을 바꿔야 합니다.

작업이 완료되면 DocList Manager 프로젝트의 핵심인 DoclistControllerApplicationController를 확인해 보세요. 또한 Google 주소록 API 호출을 처리하는 ContactsController도 살펴볼 수 있습니다.

마무리

Google 데이터 레일 앱을 만드는 데 가장 어려운 부분은 레일 구성입니다. 하지만 1초는 애플리케이션을 배포하는 것입니다. 이를 위해 Apache용 mod_rails를 사용하는 것이 좋습니다. 설정, 설치, 실행도 매우 쉽습니다. 이제 바로 사용할 수 있습니다.

자료

부록

DocList Manager는 이 문서에서 다루는 주제를 보여주는 전체 Ruby on 레일 샘플입니다. 전체 소스 코드는 프로젝트 호스팅에서 제공됩니다.