بيانات Google حول السكك الحديدية

إريك بيدلمان، فريق Google Data APIs
شباط (فبراير) 2009

المقدمة

"Where's Ruby is on the list of client مكتبات? "

بدافع من حماسة مطوّري البرامج وشعبية Ruby on السكك الحديدية (ROR) المتواصلة، أنشأ زميلي جيف فيشر مكتبة لمستلزمات لعبة Ruby من أعماق جبل Doom. ضع في اعتبارك أنها ليست مكتبة عميلة كاملة، ولكنها ستتعامل مع الأساسيات مثل المصادقة ومعالجة XML الأساسية. ويتطلّب ذلك أيضًا العمل مباشرةً مع خلاصة Atom باستخدام وحدة REXML وXPath.

الجمهور

هذه المقالة مُعدّة لمطوّري البرامج المهتمين بالوصول إلى واجهات برمجة تطبيقات بيانات Google باستخدام Ruby، خاصة Ruby على السكك الحديدية. وتفترض أنّ القارئ على دراية بلغة برمجة Ruby وإطار عمل تطوير خدمات "السكة الحديدية" على الويب. أركز على واجهة برمجة التطبيقات لقائمة المستندات لمعظم النماذج، ولكن يمكن تطبيق المفاهيم نفسها على أي من واجهات برمجة التطبيقات للبيانات.

البدء

المتطلّبات

  • إصدار 1.8.6 لروبي من المستوى 114 أو أكثر تنزيل
  • RubyGems 1.3.1 أو الأحدث تنزيل
  • السكة الحديدية 2.2.2+ تنزيل

تثبيت مكتبة أداة Google Ruby في Google Data

للحصول على المكتبة، يمكنك إما تنزيل مصدر المكتبة مباشرة من استضافة المشروع أو تثبيت الأداة:

sudo gem install gdata

نصيحة: للحصول على قياس جيد، شغّل gem list --local للتحقق من تثبيت الجوهرة بشكل صحيح.

المصادقة

ClientLogin

يتيح ClientLogin لتطبيقك تسجيل دخول المستخدمين آليًا إلى حساباتهم على Google أو G Suite. عند التحقق من بيانات اعتماد المستخدم، تصدر Google رمز مصادقة مميزًا لتتم الإشارة إليه في طلبات واجهة برمجة التطبيقات التالية. يظل الرمز المميز صالحًا لمدة زمنية محددة، يتم تحديدها من خلال أي خدمة من خدمات Google تعمل معها. لأسباب أمنية ولتوفير أفضل تجربة للمستخدمين، يجب ألا تستخدم ClientLogin إلا عند تطوير تطبيقات سطح المكتب المثبتة. بالنسبة إلى تطبيقات الويب، يُفضَّل استخدام AuthSub أو OAuth.

تحتوي مكتبة Ruby على فئة عميل لكل واجهة من واجهات برمجة التطبيقات. على سبيل المثال، استخدم مقتطف الرمز التالي لتسجيل الدخول 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]

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 و AuthSubإبطالToken لإدارة الرموز المميّزة. 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 كمتعاون إلى المستند الذي يحمل المعرّف: 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:أو إدخال آخر من البيانات من الخادم، استخدم طريقة 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)

إنشاء تطبيق جديد لخطوط السكك الحديدية

عادةً ما يتطلب الأمر الأول عند إنشاء تطبيق السكك الحديدية الجديد تشغيل مولدات السقالات لإنشاء ملفات MVC. بعد ذلك، يتم تشغيل rake db:migrate لإعداد جداول قاعدة البيانات. ومع ذلك، ونظرًا لأن تطبيقنا سيبحث في واجهة برمجة التطبيقات لقائمة مستندات Google عن البيانات، فلم نعد بحاجة إلى أي سقالات أو قواعد بيانات عامة. بدلاً من ذلك، أنشئ تطبيقًا جديدًا ووحدة تحكم بسيطة:

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، الذي يتعامل مع المكالمات الواردة إلى واجهة برمجة تطبيقات "جهات اتصال Google".

الخاتمة

أصعب شيء في إنشاء تطبيق Google Datarails هو تهيئة Trains! ومع ذلك، تتمثّل الخطوة الثانية في نشر تطبيقك. ولذلك، أوصي بشدة باستخدام mod_rails لنظام Apache. من السهل جدًا إعداده وتثبيته وتشغيله. ستتمكن من البدء في وقت قصير!

الموارد

الملحق

أمثلة

يعتبر DocList Manager نموذجًا كاملاً لـ Ruby on السكك الحديدية يوضح الموضوعات التي تمت مناقشتها في هذه المقالة. تتوفر شفرة المصدر الكاملة من خلال استضافة المشروع.