Google 데이터 가젯 만들기

에릭 비델만, Google 데이터 API팀
2008년 10월

소개

대상

이 도움말에서는 Blogger 가젯 만들기에 대해 설명합니다. 여기서는 사용자가 Google Data API자바스크립트 클라이언트 라이브러리에 익숙하다고 가정합니다. 또한 자바스크립트에 능통하며 가젯*을 사용하여 오픈소셜 가젯 구현 경험이 있어야 합니다. API를 참조하세요.

또한 이 예는 가젯에서 외부 라이브러리를 사용하는 방법을 보여줍니다. jQuery(주로 UI 효과)와 TinyMCE(훌륭한 WYSIWYG 서식 있는 텍스트 편집기 플러그인)를 사용했습니다.

동기

Google 데이터 API 중 하나를 사용하여 JSON을 사용하는 가젯은 자바스크립트를 거의 작성할 필요가 없습니다. 이러한 가젯의 가장 큰 단점은 데이터가 공개 상태이고 읽기 전용이라는 점입니다. 더 흥미로운 가젯으로 빌드하려면 사용자의 비공개 데이터 (인증이 필요함)에 액세스해야 합니다. 지금까지는 Google Account API를 활용할 수 있는 효과적인 방법이 없었습니다. AuthSub를 사용하려면 브라우저 리디렉션이 필요하고 ClientLogin이 사용자 인증 정보를 클라이언트 측에 노출합니다. type="url" 가젯도 해킹하기 어려웠습니다.

OAuth 프록시를 입력합니다.

OAuth 프록시

OAuth에 익숙하지 않은 경우, 사용자가 비공개 데이터를 다른 웹사이트 또는 가젯과 공유하도록 허용하는 인증 표준입니다. OAuth 사양을 준수하려면 모든 데이터 요청에 디지털 서명이 필요합니다. 이 방식은 보안에 매우 유용하지만, 자바스크립트 가젯에서는 비공개 키를 관리하고 디지털 서명을 생성하는 것이 안전하지 않습니다. 또한 교차 도메인 문제가 더 복잡합니다.

다행히 이러한 문제는 OAuth 프록시라는 가젯 플랫폼의 기능을 활용하여 해결됩니다. OAuth 프록시는 가젯 개발자가 더 쉽게 작업할 수 있도록 설계되었습니다. OAuth 인증 세부정보의 많은 부분을 숨기고 복잡한 작업을 대신 수행합니다. 프록시는 가젯 대신 데이터 요청에 서명하므로 비공개 키를 관리하거나 서명 요청에 대해 걱정할 필요가 없습니다. 그냥 사용하면 됩니다.

OAuth 프록시는 가젯 사양의 구현인 Shindig라는 오픈소스 프로젝트를 기반으로 합니다.

참고: OAuth 프록시는 gadgets.* API를 사용하고 오픈소셜 컨테이너에서 실행되는 가젯에만 지원됩니다. 기존 가젯 API에는 지원되지 않습니다.

시작하기

이 튜토리얼의 나머지 부분에서는 사용자의 Blogger 데이터에 액세스하는 가젯 작성에 중점을 둡니다. OAuth 프록시를 사용한 인증, 자바스크립트 클라이언트 라이브러리를 사용한 후 마지막으로 Blogger에 항목을 게시합니다.

인증

먼저 가젯에 OAuth를 사용하도록 지시해야 합니다. 이렇게 하려면 가젯의 <ModulePrefs> 섹션에 <OAuth> 요소를 추가합니다.

<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>

<Service> 요소의 URL 엔드포인트 3개는 Google의 OAuth 토큰 엔드포인트에 해당합니다. 쿼리 매개변수에 대한 설명은 다음과 같습니다.

  • scope

    이 매개변수는 요청 URL에 필요합니다. 가젯은 이 매개변수에 사용된 scope의 데이터에만 액세스할 수 있습니다. 이 예에서 가젯은 Blogger에 액세스합니다. 가젯이 2개 이상의 Google Data API에 액세스하려고 하면 추가 scope%20와 연결합니다. 예를 들어 Calendar와 Blogger에 모두 액세스하려면 범위를 http://www.blogger.com/feeds/%20http://www.google.com/calendar/feeds/로 설정합니다.

  • oauth_callback

    이 매개변수는 Authorization URL에서 선택사항입니다. 사용자가 데이터에 대한 액세스를 승인하면 OAuth 승인 페이지가 이 URL로 리디렉션됩니다. 이 매개변수를 그대로 두거나 '승인된 페이지'로 설정하거나 http://oauth.gmodules.com/gadgets/oauthcallback를 사용할 수 있습니다. 후반부에서 사용자가 처음으로 라이브러리를 설치할 때 최상의 사용자 환경을 제공합니다. 해당 페이지는 팝업 창을 자동으로 닫는 자바스크립트 스니펫을 제공합니다.

OAuth를 사용하는 가젯이 있으므로 사용자는 자신의 데이터에 대한 액세스를 승인해야 합니다. 인증 흐름은 다음과 같습니다.

  1. 가젯이 처음으로 로드되고 사용자의 Blogger 데이터에 액세스하려고 시도합니다.
  2. 사용자가 가젯에 대한 액세스 권한을 부여하지 않았으므로 요청이 실패합니다. 다행히 응답에 반환된 객체에는 사용자를 로그인에 보내는 URL(response.oauthApprovalUrl)이 포함되어 있습니다. 가젯이 'Blogger에 로그인'을 표시하고 href를 oauthApprovalUrl 값으로 설정합니다.
  3. 그런 다음 사용자가 'Blogger에 로그인'을 클릭하면 별도의 창에 OAuth 승인 페이지가 열립니다. 가젯은 사용자가 '액세스가 승인되었습니다'라는 링크를 표시하여 승인 절차를 마칠 때까지 기다립니다.
  4. 팝업에서 사용자는 가젯에 대한 액세스를 허용 또는 거부하도록 선택합니다. '액세스 권한 부여'를 클릭하면 http://oauth.gmodules.com/gadgets/oauthcallback으로 이동되고 창이 닫힙니다.
  5. 창이 닫힌 것을 인식하여 사용자 데이터를 다시 요청하여 Blogger에 다시 액세스를 시도합니다. 창 닫기를 감지하기 위해 팝업 핸들러를 사용했습니다. 이러한 코드를 사용하지 않으면 사용자가 '액세스가 승인되었습니다'를 직접 클릭할 수 있습니다.
  6. 이제 가젯이 일반 UI를 표시합니다. 이 보기는 IssuedAuthSubTokens에서 인증 토큰이 취소되지 않는 한 지속됩니다.

따라서 위 단계를 통해 가젯은 세 가지 서로 다른 상태에 대한 개념을 갖게 됩니다.

  1. 인증되지 않았습니다. 사용자가 승인 절차를 시작해야 합니다.
  2. 사용자가 데이터 액세스를 승인할 때까지 기다리는 중입니다.
  3. 인증되었습니다. 가젯은 정상적인 기능을 표시합니다.

가젯에서 <div> 컨테이너를 사용하여 각 단계를 분리했습니다.

<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>

<div>showOnly()를 사용하여 단독으로 표시됩니다. 이 기능에 대한 자세한 내용은 전체 가젯 예를 참조하세요.

자바스크립트 클라이언트 라이브러리 사용

OpenSocial에서 원격 콘텐츠를 가져오려면 gadgets.* API를 사용하여 gadgets.io.makeRequest 메서드를 호출합니다. 하지만 Google 데이터 가젯은 빌드 중이므로 gadgets.io.* API를 건드리지 않아도 됩니다. 대신 각 Google 데이터 서비스에 요청을 보내는 특별한 메서드가 있는 자바스크립트 클라이언트 라이브러리를 활용하세요.

참고: 이 문서 작성 시점을 기준으로 자바스크립트 라이브러리는 Blogger, Calendar, 주소록, Finance, Google Base만 지원합니다. 다른 API 중 하나를 사용하려면 라이브러리 없이 gadgets.io.makeRequest를 사용합니다.

라이브러리 로드

자바스크립트 라이브러리를 로드하려면 <Content> 섹션에 공통 로더를 포함하고 가젯이 초기화된 후 라이브러리를 가져옵니다. gadgets.util.registerOnLoadHandler()에 콜백을 제공하면 가젯이 준비되는 데 도움이 됩니다.

<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>

blogger.useOAuth('google') 호출은 일반 인증 방법인 AuthSubJS 대신 OAuth 프록시를 사용하도록 라이브러리에 지시합니다. 마지막으로 가젯은 fetchData()를 호출하여 사용자의 Blogger 데이터를 검색합니다. 이 메서드는 아래에 정의되어 있습니다.

데이터를 가져오는 중입니다.

모든 설정이 완료되었으므로 데이터를 실제로 GET 또는 POST하려면 어떻게 해야 할까요?

오픈소셜의 일반적인 패러다임은 가젯에서 fetchData()라는 함수를 정의하는 것입니다. 이 메서드는 일반적으로 인증의 여러 단계를 처리하고 gadgets.io.makeRequest를 사용하여 데이터를 가져옵니다. 자바스크립트 클라이언트 라이브러리를 사용하고 있으므로 gadgets.io.makeRequestblogger.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);
}

이 함수가 두 번째로 호출되면 response.feed에 데이터가 포함됩니다.

참고: getBlogFeed()는 콜백 및 오류 핸들러에 동일한 함수를 사용합니다.

Blogger에 항목 게시

마지막 단계는 블로그에 새 항목을 게시하는 것입니다. 아래 코드는 사용자가 '저장' 버튼을 클릭하면 어떻게 되는지 보여줍니다.

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);
}

마무리

이제 Google 데이터 API를 기반으로 가젯 코딩을 시작할 수 있습니다.

이 도움말로 OAuth 프록시가 얼마나 간단하게 가젯 인증을 수행하는지 이해하셨기를 바랍니다. 이 강력한 도구를 Google 데이터 자바스크립트 클라이언트 라이브러리와 결합하면 흥미롭고 대화형이며 정교한 가젯도 쉽게 빌드할 수 있습니다.

이 도움말에 대한 질문이나 의견이 있는 경우 Google Accounts API 토론 포럼을 방문하세요.

자료