Membuat Gadget Data Google

Eric Bidelman, tim Google Data API
Oktober 2008

Pengantar

Audiens

Artikel ini akan memandu Anda membuat gadget Blogger. Anda dianggap sudah memahami Google Data API dan library klien JavaScript. Anda harus fasih dalam JavaScript dan memiliki pengalaman mengimplementasikan gadget OpenSocial menggunakan gadget.* API.

Contoh ini juga menunjukkan cara berhasil menggunakan library eksternal di gadget Anda. Saya telah menggunakan jQuery (terutama untuk efek UI-nya) dan TinyMCE, plugin editor rich text WYSIWYG yang hebat.

Motivasi

Cara membuat gadget yang menggunakan JSON dengan salah satu Google Data API sangat sedikit. Kekebalan utama gadget semacam ini adalah bahwa data bersifat publik dan hanya-baca. Untuk membuat gadget yang lebih menarik, Anda memerlukan akses ke data pribadi pengguna (sesuatu yang memerlukan autentikasi). Sejauh ini, belum ada cara yang bagus untuk memanfaatkan Google Account API. AuthSub memerlukan pengalihan browser dan ClientLogin yang mengekspos kredensial pengguna dan sisi klien. Bahkan meretas gadget type="url" tidak nyaman.

Masukkan Proxy OAuth.

Proxy OAuth

Jika Anda tidak terbiasa dengan OAuth, standar autentikasi yang memungkinkan pengguna membagikan data pribadi mereka dengan situs atau gadget lain. Spesifikasi OAuth mengharuskan semua permintaan data ditandatangani secara digital. Ini bagus untuk keamanan, namun untuk gadget JavaScript, mengelola kunci pribadi dan membuat tanda tangan digital tidak aman. Ada juga detail tambahan dari masalah lintas-domain.

Untungnya, masalah ini diselesaikan dengan memanfaatkan fitur dari platform gadget yang disebut Proxy OAuth. Proxy OAuth dirancang untuk memudahkan developer gadget. Fungsi ini menyembunyikan banyak detail autentikasi OAuth dan dapat melakukan bagian yang sulit untuk Anda. Proxy menandatangani permintaan data atas nama gadget Anda, sehingga tidak perlu mengelola kunci pribadi atau khawatir tentang permintaan penandatanganan. Berhasil!

Proxy OAuth didasarkan pada project open source yang bernama Shindig, yang merupakan implementasi dari spesifikasi gadget.

Catatan: Proxy OAuth hanya didukung untuk gadget yang menggunakan gadgets.* API dan berjalan di penampung OpenSocial. API ini tidak didukung untuk API gadget lama.

Memulai

Bagian selanjutnya dari tutorial ini akan berfokus pada pembuatan gadget untuk mengakses data Blogger pengguna. Kita akan menelusuri autentikasi (menggunakan Proxy OAuth), menggunakan library klien JavaScript, dan terakhir, memposting entri ke Blogger.

Autentikasi

Pertama-tama, kita perlu memberi tahu gadget untuk menggunakan OAuth. Untuk melakukannya, tambahkan elemen <OAuth> di bagian <ModulePrefs> gadget:

<ModulePrefs>
...
<OAuth>
  <Service name="google">
    <Access url="https://www.google.com/accounts/OAuthGetAccessToken" method="GET" /> 
    <Request url="https://www.google.com/accounts/OAuthGetRequestToken?scope=http://www.blogger.com/feeds/" method="GET" /> 
    <Authorization url="https://www.google.com/accounts/OAuthAuthorizeToken?
                        oauth_callback=http://oauth.gmodules.com/gadgets/oauthcallback" /> 
  </Service>
</OAuth>
...
</ModulePrefs>

Tiga endpoint URL dalam elemen <Service> sesuai dengan endpoint token OAuth Google. Berikut adalah penjelasan tentang parameter kueri:

  • scope

    Parameter ini wajib ada di URL Permintaan. Gadget Anda hanya dapat mengakses data dari scope yang digunakan dalam parameter ini. Dalam contoh ini, gadget akan mengakses Blogger. Jika gadget Anda ingin mengakses lebih dari satu Google Data API, gabungkan scope tambahan dengan %20. Contohnya, jika Anda ingin mengakses Kalender dan Blogger, tetapkan cakupan ke http://www.blogger.com/feeds/%20http://www.google.com/calendar/feeds/.

  • oauth_callback

    Parameter ini opsional di URL Otorisasi. Halaman persetujuan OAuth akan dialihkan ke URL ini setelah pengguna menyetujui akses ke data mereka. Anda dapat memilih untuk tidak menyertakan parameter ini, menetapkannya ke "halaman yang disetujui", atau sebaiknya gunakan http://oauth.gmodules.com/gadgets/oauthcallback. Selanjutnya, akan memberikan pengalaman pengguna terbaik saat pengguna menginstal gadget untuk pertama kali. Halaman tersebut menyediakan cuplikan JavaScript yang secara otomatis menutup jendela pop-up.

Setelah kita memiliki gadget menggunakan OAuth, pengguna harus menyetujui akses ke data mereka. Berikut adalah alur autentikasi:

  1. Gadget akan dimuat untuk pertama kalinya dan berupaya mengakses data Blogger pengguna.
  2. Permintaan gagal karena pengguna belum memberikan akses ke gadget. Untungnya, objek yang ditampilkan dalam respons berisi URL (response.oauthApprovalUrl) tempat kita akan mengarahkan pengguna untuk login. Gadget menampilkan "Login ke Blogger" dan setel href-nya ke nilai oauthApprovalUrl.
  3. Selanjutnya, pengguna mengklik "Login ke Blogger" dan halaman persetujuan OAuth akan terbuka di jendela terpisah. Gadget menunggu pengguna menyelesaikan proses persetujuan dengan menampilkan link: "Saya telah menyetujui akses".
  4. Di jendela pop-up, pengguna akan memilih untuk memberikan/menolak akses ke gadget kami. Setelah mengklik "Berikan akses", pengguna akan diarahkan ke http://oauth.gmodules.com/gadgets/oauthcallback dan jendela ditutup.
  5. Gadget akan mengenali jendela tertutup dan mencoba mengakses Blogger untuk kedua kalinya dengan meminta kembali data pengguna. Untuk mendeteksi penutupan jendela, saya telah menggunakan pengendali pop-up. Jika tidak menggunakan kode tersebut, pengguna dapat mengklik "Saya telah menyetujui akses" secara manual.
  6. Sekarang gadget menampilkan UI normal. Tampilan ini akan tetap ada kecuali jika token autentikasi dicabut di bagian Issue Streaming.

Jadi dari langkah-langkah di atas, gadget memiliki gagasan tentang tiga status yang berbeda:

  1. Tidak diautentikasi. Pengguna harus memulai proses persetujuan.
  2. Menunggu pengguna menyetujui akses ke data mereka.
  3. Diautentikasi. Gadget menampilkan status fungsi normal.

Di gadget, saya telah menggunakan <div> penampung untuk memisahkan setiap tahap:

<Content type="html">
<![CDATA[

<!-- Normal state of the gadget. The user is authenticated -->       
<div id="main" style="display:none">
  <form id="postForm" name="postForm" onsubmit="savePost(this); return false;">
     <div id="messages" style="display: none"></div>
     <div class="selectFeed">Publish to:
       <select id="postFeedUri" name="postFeedUri" disabled="disabled"><option>loading blog list...</option></select>
     </div>
     <h4 style="clear:both">Title</h4>
     <input type="text" id="title" name="title"/>
     <h4>Content</h4>
     <textarea id="content" name="content" style="width:100%;height:200px;"></textarea>
     <h4 style="float:left;">Labels (comma separated)</h4><img src="blogger.png" style="float:right"/>
     <input type="text" id="categories" name="categories"/>
     <p><input type="submit" id="submitButton" value="Save"/> 
     <input type="checkbox" id="draft" name="draft" checked="checked"/> <label for="draft">Draft?</label></p>
  </form>
</div>

<div id="approval" style="display: none">
  <a href="#" id="personalize">Sign in to Blogger</a>
</div>

<div id="waiting" style="display: none">
  <a href="#" id="approvalLink">I've approved access</a>
</di

<!-- An errors section is not necessary but great to have -->
<div id="errors" style="display: none"></div>
 
<!-- Also not necessary, but great for informing users -->     
<div id="loading">
  <h3>Loading...</h3>
  <p><img src="ajax-loader.gif"></p>
</div>

]]> 
</Content>

Setiap <div> ditampilkan dengan sendirinya menggunakan showOnly(). Lihat gadget contoh lengkap untuk detail tentang fungsi tersebut.

Menggunakan library klien JavaScript

Untuk mengambil konten jarak jauh di OpenSocial, Anda akan melakukan panggilan ke metode gadgets.io.makeRequest menggunakan gadgets.* API. Namun, karena kita sedang membuat gadget Data Google, Anda tidak perlu menyentuh API gadgets.io.*. Sebagai gantinya, manfaatkan library klien JavaScript yang memiliki metode khusus untuk membuat permintaan ke setiap layanan Data Google.

Catatan: Pada saat artikel ini ditulis, library JavaScript hanya mendukung Blogger, Calendar, Contacts, Finance, dan Google Base. Untuk menggunakan salah satu API lain, gunakan gadgets.io.makeRequest tanpa library.

Memuat library

Untuk memuat library JavaScript, sertakan loader umum di bagian <Content>, lalu impor library setelah gadget diinisialisasi. Mengirimkan callback ke gadgets.util.registerOnLoadHandler() akan membantu menentukan kapan gadget siap:

<Content type="html">
<![CDATA[
  ...
  <script src="https://www.google.com/jsapi"></script>
  <script type="text/javascript">
  var blogger = null;  // make our service object global for later
  
  // Load the JS library and try to fetch data once it's ready
  function initGadget() {  
    google.load('gdata', '1.x', {packages: ['blogger']});  // Save overhead, only load the Blogger service
    google.setOnLoadCallback(function () {
      blogger = new google.gdata.blogger.BloggerService('google-BloggerGadget-v1.0');
      blogger.useOAuth('google');
      fetchData();
    });
  }
  gadgets.util.registerOnLoadHandler(initGadget);
  </script>
  ...
]]> 
</Content>

Panggilan ke blogger.useOAuth('google') memberi tahu library untuk menggunakan Proxy OAuth (bukan AuthSubJS - metode autentikasi normalnya). Terakhir, gadget mencoba mengambil data Blogger pengguna dengan memanggil fetchData(). Metode tersebut ditetapkan di bawah.

Mengambil data

Setelah semuanya siap, bagaimana sebenarnya cara GET atau POST data ke Blogger?

Paradigma umum di OpenSocial adalah menentukan fungsi yang disebut fetchData() di gadget Anda. Metode ini biasanya menangani berbagai tahap autentikasi dan mengambil data menggunakan gadgets.io.makeRequest. Karena kita menggunakan library klien JavaScript, gadgets.io.makeRequest akan diganti dengan panggilan ke blogger.getBlogFeed():

function fetchData() {
  jQuery('#errors').hide();
  
  var callback = function(response) {
    if (response.oauthApprovalUrl) {
      // You can set the sign in link directly:
      // jQuery('#personalize').get(0).href = response.oauthApprovalUrl
      
      // OR use the popup.js handler
      var popup = shindig.oauth.popup({
        destination: response.oauthApprovalUrl,
        windowOptions: 'height=600,width=800',
        onOpen: function() {
          showOnly('waiting');
        },
        onClose: function() {
          showOnly('loading');
          fetchData();
        }
      });
      jQuery('#personalize').get(0).onclick = popup.createOpenerOnClick();
      jQuery('#approvalLink').get(0).onclick = popup.createApprovedOnClick();
      
      showOnly('approval');
    } else if (response.feed) {
      showResults(response);
      showOnly('main');
    } else {
      jQuery('#errors').html('Something went wrong').fadeIn();
      showOnly('errors');
    }
  };
  
  blogger.getBlogFeed('http://www.blogger.com/feeds/default/blogs', callback, callback);
}

Kali kedua fungsi ini dipanggil, response.feed berisi data.

Catatan: getBlogFeed() menggunakan fungsi yang sama untuk callback dan pengendali error-nya.

Posting entri ke Blogger

Langkah terakhir adalah memposting entri baru ke Blog. Kode di bawah ini menunjukkan apa yang terjadi saat pengguna mengklik tombol "Simpan".

function savePost(form) { 
  jQuery('#messages').fadeOut();
  jQuery('#submitButton').val('Publishing...').attr('disabled', 'disabled');
  
  // trim whitespace from the input tags
  var input = form.categories.value;
  var categories = jQuery.trim(input) != '' ? input.split(',') : [];   
  jQuery.each(categories, function(i, value) {
    var label = jQuery.trim(value);
    categories[i] = {
      scheme: 'http://www.blogger.com/atom/ns#',
      term: label
    };
  });

  // construct the blog post entry
  var newEntry = new google.gdata.blogger.BlogPostEntry({
    title: {
      type: 'text', 
      text: form.title.value
    },
    content: {
      type: 'text', 
      text: form.content.value
    },
    categories: categories
  });
  
  // publish as draft?
  var isDraft = form.draft.checked;
  if (isDraft) {
    newEntry.setControl({draft: {value: google.gdata.Draft.VALUE_YES}});
  }
  
  // callback for insertEntry()
  var handleInsert = function(entryRoot) {
    var entry = entryRoot.entry;
    var str = isDraft ? '(as draft)' : '<a href="' + entry.getHtmlLink().getHref() + '" target="_blankt">View it</a>';

    jQuery('#messages').html('Post published! ' + str).fadeIn();
    jQuery('#submitButton').val('Save').removeAttr('disabled');
  };
  
  // error handler for insertEntry()
  var handleError = function(e) {
    var msg = e.cause ? e.cause.statusText + ': ' : '';
    msg += e.message;
    alert('Error: ' + msg);
  };
  
  blogger.insertEntry(form.postFeedUri.value, newEntry, handleInsert, handleError);
}

Kesimpulan

Sekarang Anda memiliki elemen penyusun untuk memulai coding gadget selain Google Data API.

Semoga artikel ini memberi Anda apresiasi atas betapa sederhananya Proxy OAuth membuat autentikasi gadget. Menggabungkan alat daya ini dengan library klien JavaScript Data Google memudahkan pembuatan gadget yang menarik, interaktif, dan canggih.

Jika Anda memiliki pertanyaan atau komentar tentang artikel ini, kunjungi kami di forum diskusi Google Accounts API.

Resource