אוקטובר 2008
מבוא
קהל
במאמר הזה נסביר איך ליצור גאדג'ט ל-Blogger. ההנחה היא שאתם מכירים את Google Data APIs ואת ספריית הלקוח של JavaScript. בנוסף, צריך להיות לכם ידע ב-JavaScript וניסיון בהטמעה של גאדג'ט OpenSocial באמצעות gadgets.* API.
הדוגמה הזו גם מדגימה איך להשתמש בספריות חיצוניות בגאדג'טים. השתמשתי ב-jQuery (בעיקר בשביל אפקטים בממשק המשתמש) וב-TinyMCE, תוסף נהדר לעורך טקסט עשיר מסוג WYSIWYG.
למה בחרנו לעשות זאת?
כדי ליצור גאדג'ט שמשתמש ב-JSON עם אחד מ-Google Data APIs, צריך לכתוב מעט מאוד JavaScript. הבעיה העיקרית בגאדג'ט כזה היא שהנתונים הם ציבוריים ולקריאה בלבד. כדי ליצור גאדג'טים מעניינים יותר, צריך גישה לנתונים פרטיים של משתמש (גישה שדורשת אימות). עד עכשיו לא הייתה דרך טובה לנצל את ממשקי ה-API של חשבון Google. AuthSub דורש הפניות אוטומטיות בדפדפן, ו-ClientLogin חושף את פרטי הכניסה של המשתמש בצד הלקוח. גם פריצה לגאדג'ט type="url"
הייתה מסורבלת.
מזינים את שרת ה-Proxy של OAuth.
שרת proxy של OAuth
אם אתם לא מכירים את OAuth, זהו תקן אימות שמאפשר למשתמש לשתף את הנתונים הפרטיים שלו עם אתר או גאדג'ט אחרים. במפרט OAuth נדרש שכל בקשות הנתונים יהיו חתומות דיגיטלית. זה מצוין מבחינת אבטחה, אבל במקרה של גאדג'ט JavaScript, ניהול מפתחות פרטיים ויצירת חתימות דיגיטליות לא מאובטחים. יש גם את הבעיה המורכבת של מעקב בדומיינים שונים.
למזלנו, אפשר לפתור את הבעיות האלה באמצעות תכונה מפלטפורמת הגאדג'טים שנקראת OAuth Proxy. ה-OAuth Proxy נועד להקל על מפתחי גאדג'טים. היא מסתירה חלק גדול מפרטי האימות של OAuth ומבצעת את הפעולות המורכבות בשבילכם. ה-Proxy חותם על בקשות נתונים בשם הגאדג'ט, כך שאין צורך לנהל מפתחות פרטיים או לדאוג לחתימה על בקשות. פשוט עובד!
שרת ה-proxy של OAuth מבוסס על פרויקט קוד פתוח שנקרא Shindig, שהוא הטמעה של מפרט הגאדג'טים.
הערה: ה-OAuth Proxy נתמך רק בגאדג'טים שמשתמשים ב-gadgets.*
API ופועלים במאגרי OpenSocial.
הוא לא נתמך ב-legacy gadgets API.
תחילת העבודה
בהמשך המדריך הזה נתמקד ביצירת גאדג'ט לגישה לנתונים של משתמש ב-Blogger. נעבור על אימות (באמצעות OAuth Proxy), שימוש בספריית הלקוח של JavaScript ולבסוף, פרסום רשומה ב-Blogger.
אימות
קודם כל, צריך להגדיר את הגאדג'ט לשימוש ב-OAuth. כדי לעשות את זה, מוסיפים את הרכיב <OAuth>
בקטע <ModulePrefs>
של הגאדג'ט:
<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>
שלוש נקודות הקצה של כתובות ה-URL ברכיב <Service>
תואמות לנקודות הקצה של טוקן OAuth של Google. הסבר על הפרמטרים של השאילתה:
scope
חובה לכלול את הפרמטר הזה בכתובת ה-URL של הבקשה. הגאדג'ט יוכל לגשת רק לנתונים מ-
scope
שמשמשים בפרמטר הזה. בדוגמה הזו, הגאדג'ט יגש ל-Blogger. אם הגאדג'ט רוצה לגשת ליותר מ-Google Data API אחד, צריך לשרשר אתscope
(ים) הנוספים עם a%20
. לדוגמה, אם רוצים לגשת גם ליומן וגם ל-Blogger, צריך להגדיר את ההיקף ל-http://www.blogger.com/feeds/%20http://www.google.com/calendar/feeds/
.oauth_callback
הפרמטר הזה הוא אופציונלי בכתובת ה-URL של ההרשאה. דף האישור של OAuth יפנה לכתובת ה-URL הזו אחרי שהמשתמש יאשר את הגישה לנתונים שלו. אתם יכולים לבחור להשמיט את הפרמטר הזה, להגדיר אותו ל'דף מאושר' משלכם, או עדיף להשתמש ב-
http://oauth.gmodules.com/gadgets/oauthcallback
. האפשרות השנייה מספקת את חוויית המשתמש הטובה ביותר כשמשתמשים מתקינים את הגאדג'ט בפעם הראשונה. בדף הזה מופיע קטע קוד JavaScript שסוגר אוטומטית את החלון הקופץ.
עכשיו, אחרי שהגדרנו את הגאדג'ט שלנו לשימוש ב-OAuth, המשתמש צריך לאשר את הגישה לנתונים שלו. תהליך האימות:
- הגאדג'ט נטען בפעם הראשונה ומנסה לגשת לנתוני Blogger של המשתמש.
- הבקשה נכשלת כי המשתמש לא העניק גישה לגאדג'ט. למזלנו, האובייקט שמוחזר בתגובה מכיל כתובת URL (
response.oauthApprovalUrl
) שאליה נשלח את המשתמש כדי להתחבר. הגאדג'ט מציג את האפשרות 'כניסה ל-Blogger' ומגדיר את הערך שלoauthApprovalUrl
כ-href שלו. - לאחר מכן, המשתמש לוחץ על 'כניסה ל-Blogger' ודף האישור של OAuth נפתח בחלון נפרד. הגאדג'ט ממתין שהמשתמש יסיים את תהליך האישור ומציג קישור: "אישרתי את הגישה".
- בחלון הקופץ, המשתמש יבחר אם להעניק גישה לגאדג'ט שלנו או לדחות את הבקשה. אחרי שהם לוחצים על 'מתן גישה', הם מועברים אל
http://oauth.gmodules.com/gadgets/oauthcallback
והחלון נסגר. - הגאדג'ט מזהה שהחלון נסגר ומנסה לגשת ל-Blogger בפעם השנייה על ידי שליחת בקשה חוזרת לנתוני המשתמש. כדי לזהות את סגירת החלון, השתמשתי בhandler לחלון קופץ. אם לא משתמשים בקוד כזה, המשתמש יכול ללחוץ באופן ידני על 'אישרתי את הגישה'.
- הגאדג'ט יציג עכשיו את ממשק המשתמש הרגיל שלו. התצוגה הזו תישאר אלא אם טוקן האימות יבוטל בקטע IssuedAuthSubTokens.
לכן, מהשלבים שלמעלה, אפשר לראות שלגאדג'טים יש שלושה מצבים שונים:
- לא מאומת. המשתמש צריך להתחיל את תהליך האישור.
- ממתינים שהמשתמש יאשר גישה לנתונים שלו.
- בוצע אימות. הגאדג'ט מציג את מצב הפעולה הרגיל שלו.
בגאדג'ט שלי השתמשתי ב<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()
. פרטים על הפונקציה הזו מופיעים בדוגמה מלאה לגאדג'ט.
שימוש בספריית הלקוח של JavaScript
כדי לאחזר תוכן מרחוק ב-OpenSocial, מבצעים קריאה ל-method gadgets.io.makeRequest
באמצעות gadgets.*
API.
עם זאת, מכיוון שאנחנו בונים גאדג'ט של Google Data, אין צורך להשתמש בממשקי ה-API של gadgets.io.*
. במקום זאת, אפשר להשתמש בספריית הלקוח של JavaScript, שכוללת שיטות מיוחדות לשליחת בקשות לכל שירות נתונים של Google.
הערה: בזמן כתיבת המאמר הזה, ספריית JavaScript תומכת רק ב-Blogger, ביומן, באנשי קשר, בFinance וב-Google Base. כדי להשתמש באחד מממשקי ה-API האחרים, צריך להשתמש ב-gadgets.io.makeRequest
בלי הספרייה.
טעינת הספרייה
כדי לטעון את ספריית ה-JavaScript, צריך לכלול את טוען המשותף בקטע <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')
אומרת לספרייה להשתמש ב-OAuth Proxy (במקום ב-AuthSubJS – שיטת האימות הרגילה שלה).
לבסוף, הווידג'ט מנסה לאחזר את נתוני המשתמש ב-Blogger על ידי קריאה ל-fetchData()
. השיטה הזו מוגדרת בהמשך.
אחזור נתונים
אחרי שמסיימים את ההגדרה, איך בעצם GET
או POST
נתונים ל-Blogger?
פרדיגמה נפוצה ב-OpenSocial היא להגדיר פונקציה בשם fetchData()
בגאדג'ט. בשיטה הזו בדרך כלל מטפלים בשלבים השונים של האימות ומביאים נתונים באמצעות gadgets.io.makeRequest
. מכיוון שאנחנו משתמשים בספריית הלקוח של JavaScript, הקריאה ל-gadgets.io.makeRequest
מוחלפת בקריאה ל-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); }
בפעם השנייה שקוראים לפונקציה הזו, 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 Data APIs.
אנחנו מקווים שהמאמר הזה עזר לכם להבין כמה פשוט לאמת גאדג'טים באמצעות OAuth Proxy. השילוב של כלי רב-עוצמה זה עם ספריית הלקוח של Google Data JavaScript מאפשר ליצור בקלות גאדג'טים מעניינים, אינטראקטיביים ומתוחכמים.
אם יש לכם שאלות או הערות לגבי המאמר הזה, אתם מוזמנים להיכנס לפורום הדיונים בנושא ממשקי API של חשבונות Google.
משאבים
- כתיבת גאדג'טים של OAuth (התיעוד המלא של גאדג'טים)
- שימוש ב-OAuth עם Google Data APIs (מאמר בנושא שימוש ב-OAuth עם Google Data APIs)
- אימות OAuth לאפליקציות אינטרנט (תיעוד מלא של OAuth)
- ספריית לקוח של JavaScript
- פורום הדיונים של Google Accounts APIs