กุมภาพันธ์ 2009
บทนำ
"ที่ใดคือ Ruby ในรายการไลบรารีของไคลเอ็นต์"
ความกระตือรือร้นของนักพัฒนาแอปที่เพิ่มสูงขึ้นและความนิยมที่แพร่หลายของ Ruby on Rails (RoR) ทําให้เพื่อนร่วมงานของฉัน Jeff Fisher สร้างไลบรารีสาธารณูปโภคของ Ruby จากความลึกของภูเขา Doom โปรดทราบว่าไม่ใช่ไลบรารีของไคลเอ็นต์อย่างเต็มรูปแบบ แต่เป็นการจัดการพื้นฐาน เช่น การตรวจสอบสิทธิ์และการบิดเบือน XML พื้นฐาน นอกจากนี้ คุณยังต้องทํางานร่วมกับฟีด Atom โดยตรงโดยใช้โมดูล REXML และ XPath
ผู้ชม
บทความนี้มีไว้สําหรับนักพัฒนาซอฟต์แวร์ที่สนใจเข้าถึง Google Data API โดยใช้ Ruby โดยเฉพาะ Ruby บน Rails และสมมติว่าผู้อ่านคุ้นเคยกับภาษาโปรแกรม Ruby และเฟรมเวิร์กการพัฒนาเว็บรถไฟของ Rails ฉันมุ่งเน้นที่ API รายชื่อเอกสารสําหรับตัวอย่างส่วนใหญ่ แต่แนวคิดเดียวกันสามารถใช้กับ Data API
เริ่มต้นใช้งาน
ข้อกำหนด
การติดตั้งไลบรารีข้อมูล Ruby Utility
หากต้องการรับไลบรารี คุณสามารถดาวน์โหลดแหล่งที่มาของไลบรารีจากการโฮสต์โปรเจ็กต์หรือติดตั้ง gem ได้โดยตรง
sudo gem install gdata
เคล็ดลับ: สําหรับการวัดที่ดี ให้เรียกใช้ gem list --local
เพื่อยืนยันว่าติดตั้งอัญมณีอย่างถูกต้องแล้ว
การตรวจสอบสิทธิ์
ClientLogin
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 ในเอกสารประกอบการตรวจสอบสิทธิ์สําหรับแอปพลิเคชันที่ติดตั้งทั้งหมด
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 มีเครื่องจัดการเพิ่มเติม 2 รายการ ได้แก่ AuthSubTokenInfo และ AuthSubDebugToken สําหรับการจัดการโทเค็น AuthSubTokenInfo
มีประโยชน์สําหรับการตรวจสอบความถูกต้องของโทเค็น AuthSubRevokeToken
มีตัวเลือกในการเข้าถึงข้อมูลของผู้ใช้ แอปของคุณควรใช้ AuthSubRevokeToken
แนวทางปฏิบัติแนะนํา ไลบรารี Ruby รองรับทั้ง 2 วิธี
วิธีค้นหาข้อมูลเมตาของโทเค็น
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
เป็นผู้ทํางานร่วมกันในเอกสารที่มีรหัส 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
เพื่อตั้งค่าตารางฐานข้อมูล แต่เนื่องจากแอปพลิเคชันของเราจะค้นหา Google Docs 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
ออกจากแอปพลิเคชัน
บรรทัดที่ 2 โหลด 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
ซึ่งจัดการการเรียก Google Contacts API ด้วย
บทสรุป
ส่วนที่ยากที่สุดในการสร้างแอป Google Data Rails คือการกําหนดค่า Rails! อย่างไรก็ตาม การปิดวินาทีทําให้แอปพลิเคชันของคุณใช้งานได้ ขอแนะนําอย่างยิ่งให้ใช้ mod_rails สําหรับ Apache ซึ่งง่ายต่อการตั้งค่า ติดตั้ง และเรียกใช้ คุณจะเริ่มทํางานได้ทันที
ทรัพยากร
- รายการ Google Data API
- หน้าโปรเจ็กต์ Google Data Ruby Utility Library
- บทความ: การใช้ Ruby กับ Google Data API
- ดาวน์โหลด Ruby
- ดาวน์โหลด RubyGems และ Rails
ภาคผนวก
ตัวอย่าง
DocList Manager เป็นตัวอย่าง Ruby on Rails แบบเต็มรูปแบบที่สาธิตหัวข้อที่กล่าวถึงในบทความนี้ ซอร์สโค้ดทั้งหมดพร้อมให้ใช้งานจากการโฮสต์โปรเจ็กต์