YQL Sample App

The YQL Sample App:

  • Demonstrates OAuth Support in Mail Applications.
  • Calls an OAuth-protected endpoint using the AuthService APIs.
  • Uses YQL.
  • Shows how to use AuthService to orchestrate user authorization for private data access.
  • Shows how to make use of Yahoo! endpoint refinements if they're enabled for your app.

Try It Out

See Quick Start to learn how to get the full source for this example, install it, and run it in Yahoo! Mail.

Introduction

The app opens in a tab when you click on its icon in the app pane. Its view has a text box where the user may enter YQL queries. When the user presses 'Go!', it passes the query to the YQL service using AuthService APIs, requesting results in JSON format. Those results are rendered in a YUI Tree View.

We will only show and talk about the AuthService parts of the sample's source here. Complete source is available from ymdt create -S 'YQL'

The OAuth Configuration File

You can obtain an OAuth key and secret by following these instructions and requesting scopes for "Contacts", "Profiles", "Mail" and any other Yahoo! services you'd like the user to authorize your app to query using YQL.

This is the auth.xml you would wind up with if you created an app from the YQL sample (i.e. if you did ymdt create -S 'YQL'). To make it work, you will need to replace insert key here with your OAuth consumer key and insert secret here with your OAuth consumer secret. Be sure to upload your changed auth.xml with ymdt!

  1. <?xml version="1.0"?>
  2. <Application>
  3. <Service name="yahoo" type="OAuth">
  4. <Consumer key = "insert key here" secret = "insert secret here"/>
  5. <Request url="https://api.login.yahoo.com/oauth/v2/get_request_token" method="GET"/>
  6. <Access url="https://api.login.yahoo.com/oauth/v2/get_token" method="GET"/>
  7. <Authorization url="https://api.login.yahoo.com/oauth/v2/request_auth"/>
  8. <Signature method="HMAC-SHA1"/>
  9. </Service>
  10. </Application>
  11.  
<?xml version="1.0"?>
<Application>
  <Service name="yahoo" type="OAuth">
    <Consumer key  =  "insert key here"  secret = "insert secret here"/>
    <Request url="https://api.login.yahoo.com/oauth/v2/get_request_token" method="GET"/>
    <Access url="https://api.login.yahoo.com/oauth/v2/get_token" method="GET"/>
    <Authorization url="https://api.login.yahoo.com/oauth/v2/request_auth"/>
    <Signature method="HMAC-SHA1"/>
  </Service>
</Application>
 

Orchestrating User Authorizaton

assets/yql.js shows how to make a web service call to execute a YQL query for private user data after orchestrating user authorization using the AuthService APIs.

Our getAuthService API can be used to interact with web services that require authorization. In the code example below, we illustrate how getAuthService() is used, to get an object to profile "oauth" (which was created together with application configuration in development tool). callWebService API is then used on the auth object to make a signed call to the Webservice.

Other AuthService APIs are used to continue the flow of authorization during a signed call. getStatus API is used to check whether logging in is required. getUserAuthorizationURL API is used to redirect the user to complete authorization process. Once the authorization is complete, notifyAuthorizationReceived API is used to initiate the retrieval of authorization token from the third-party service. removeAuthorization API removes all the keys and reverts back to intial state.

  1. YAHOO.namespace('openmail.samples.yql');
  2.  
  3. //Webservice client / user authorization wrapper
  4. // * instantiates AuthService, w/ Yahoo endpoint refinement if available
  5. // * controls UI interaction with user authorizaton call sequence
  6. YAHOO.openmail.samples.yql.ws = (function(){
  7.  
  8. //User interface abstraction from assets/ui.js
  9. var ui = YAHOO.openmail.samples.yql.ui;
  10.  
  11. //This is how you get an AuthService instance that assumes we're running in
  12. //an app with Yahoo! endpoint refinements enabled. We'll fall back to an
  13. //'unrefined' AuthService instance that uses the keys from auth.xml if this
  14. //assumption turns out to be wrong.
  15. var auth = openmail.Application.getAuthService({});
  16.  
  17. //arguments for once we get around to AuthService::callWebService
  18. var service, handler;
  19.  
  20. //AuthService.getStatus callback
  21. function onGotStatus(args){
  22.  
  23. if(args.error){
  24. ui.onError(args.error);
  25. return;
  26. }
  27.  
  28. //User hasn't yet authorized us to access their private data on the
  29. //endpoint. Fetch URL for the site where they can do that.
  30. if(args.data.status == 'authorization required'){
  31. auth.getUserAuthorizationURL({ request : {},
  32. authorization : { permissions :
  33. 'write' }},
  34. onGotAuthURL);
  35. return;
  36. }
  37.  
  38. //Status indicates we're in good shape so call YQL.
  39. auth.callWebService(service, handler);
  40. }
  41.  
  42. //AuthService.getUserAuthorizationURL callback
  43. function onGotAuthURL(args){
  44. if(args.error){
  45. ui.onError(args.error);
  46. return;
  47. }
  48. //Open user authorization site in a new window, our UI abstraction will
  49. //call us back once the user presses a button indicating that they've
  50. //wrapped things up on the external site.
  51. ui.showAuthSite(args.data.url, onAuthorizationDone);
  52. }
  53.  
  54. //ui callback after user has finished up with external site
  55. function onAuthorizationDone(){
  56. //notify the auth service that we think we're good to go
  57. auth.notifyAuthorizationReceived(onNotificationAck);
  58. }
  59.  
  60. //AuthService.notifyAuthorizationReceived callback
  61. function onNotificationAck(args){
  62. ui.hideAuthSite();
  63. if(args.error){
  64. ui.onError(args.error);
  65. return;
  66. }
  67. //AuthService is happy now, try the ws call
  68. auth.callWebService(service, handler);
  69. }
  70.  
  71. //AuthService.onRemoveAuthorization callback
  72. function onRemoveAuthorization(args){
  73. if(args.error){
  74. ui.onError(args.error);
  75. return;
  76. }
  77. }
  78.  
  79. //AuthService.callWebService callback
  80. function onFirstCalledWebService(args){
  81.  
  82. //If a Yahoo! Mail App admin hasn't enabled the Yahoo endpoint
  83. //refinement for our app, fallback to orchestrating ourselves.
  84. if(args.error && auth.profile == '_yahoo_internal'){
  85. auth = YAHOO.openmail.Application.getAuthService({ profile : 'yahoo' });
  86. }
  87.  
  88. if(args.error){
  89. //see if user authorization needed, error doesn't say
  90. auth.getStatus(onGotStatus);
  91. return;
  92. }
  93.  
  94. handler(args);
  95. }
  96.  
  97. //fire off initial status check. If all goes well, we'll eventually
  98. //auth.callWebService. If we were certain we had the Yahoo! endpoint
  99. //refinement, we could just invoke callWebService, but we want this
  100. //app to be useable even w/o that refinement.
  101. return {
  102. call : function (_service, _handler){
  103. service = _service;
  104. handler = _handler;
  105. auth.callWebService(service, onFirstCalledWebService);
  106. },
  107. logout : function(){
  108. ui.hide('logout');
  109. ui.hideAuthSite();
  110. auth.removeAuthorization(onRemoveAuthorization);
  111. }
  112. };
  113. })();
  114.  
  115.  
  116. //Invoked when user presses 'Go!' button query YQL with user input and dumps YQL
  117. //response to UI.
  118. YAHOO.openmail.samples.yql.query = (function(){
  119. var ui = YAHOO.openmail.samples.yql.ui;
  120. var callWS = YAHOO.openmail.samples.yql.ws.call;
  121.  
  122. function onYQL_Response(response){
  123. var data;
  124. if(response.error){
  125. data = '{ Result : "error querying YQL" }';
  126. ui.onError(response.error);
  127. } else{
  128. data = YAHOO.lang.JSON.parse(response.data);
  129. ui.show('logout');
  130. ui.renderYQL(data);
  131. }
  132. }
  133.  
  134. return function(){
  135. ui.hide('results');
  136. ui.hide('error');
  137. callWS({ url : 'http://query.yahooapis.com/v1/yql', method: 'GET',
  138. parameters : {format : 'json', q : ui.getQuery()}},
  139. onYQL_Response);
  140. };
  141. })();
  142.  
  143.  
  144. YAHOO.openmail.samples.yql.init = function(){
  145. YAHOO.openmail.samples.yql.ui.init();
  146. };
  147.  
  148. YAHOO.util.Event.onDOMReady(YAHOO.openmail.samples.yql.init);
YAHOO.namespace('openmail.samples.yql');
 
//Webservice client / user authorization wrapper
//    * instantiates AuthService, w/ Yahoo endpoint refinement if available
//    * controls UI interaction with user authorizaton call sequence
YAHOO.openmail.samples.yql.ws = (function(){
 
    //User interface abstraction from assets/ui.js                                     
    var ui = YAHOO.openmail.samples.yql.ui;
 
    //This is how you get an AuthService instance that assumes we're running in
    //an app with Yahoo! endpoint refinements enabled.  We'll fall back to an
    //'unrefined' AuthService instance that uses the keys from auth.xml if this
    //assumption turns out to be wrong.
    var auth = openmail.Application.getAuthService({});
 
    //arguments for once we get around to AuthService::callWebService
    var service, handler;
 
    //AuthService.getStatus callback
    function onGotStatus(args){
 
        if(args.error){
            ui.onError(args.error);
            return;
        }
 
        //User hasn't yet authorized us to access their private data on the
        //endpoint.  Fetch URL for the site where they can do that.
        if(args.data.status == 'authorization required'){
            auth.getUserAuthorizationURL({ request : {},
                                           authorization : { permissions :
                                                             'write' }},
                                         onGotAuthURL);
            return;
        }
 
        //Status indicates we're in good shape so call YQL.
        auth.callWebService(service, handler);
    }
 
    //AuthService.getUserAuthorizationURL callback
    function onGotAuthURL(args){
        if(args.error){
            ui.onError(args.error);
            return;
        }
        //Open user authorization site in a new window, our UI abstraction will
        //call us back once the user presses a button indicating that they've
        //wrapped things up on the external site.
        ui.showAuthSite(args.data.url, onAuthorizationDone);
    }
 
    //ui callback after user has finished up with external site
    function onAuthorizationDone(){
        //notify the auth service that we think we're good to go
        auth.notifyAuthorizationReceived(onNotificationAck);
    }
 
    //AuthService.notifyAuthorizationReceived callback
    function onNotificationAck(args){
        ui.hideAuthSite();
        if(args.error){
            ui.onError(args.error);
            return;
        }
        //AuthService is happy now, try the ws call
        auth.callWebService(service, handler);
    }
 
    //AuthService.onRemoveAuthorization callback
    function onRemoveAuthorization(args){
        if(args.error){
            ui.onError(args.error);
            return;
        }
    }
 
    //AuthService.callWebService callback
    function onFirstCalledWebService(args){
 
        //If a Yahoo! Mail App admin hasn't enabled the Yahoo endpoint
        //refinement for our app, fallback to orchestrating ourselves.
        if(args.error && auth.profile == '_yahoo_internal'){
            auth = YAHOO.openmail.Application.getAuthService({ profile : 'yahoo' });
        }
 
        if(args.error){
            //see if user authorization needed, error doesn't say
            auth.getStatus(onGotStatus);
            return;
        }
 
        handler(args);
    }
 
    //fire off initial status check.  If all goes well, we'll eventually
    //auth.callWebService.  If we were certain we had the Yahoo! endpoint
    //refinement, we could just invoke callWebService, but we want this
    //app to be useable even w/o that refinement.
    return { 
        call : function (_service, _handler){
            service = _service;
            handler = _handler;
            auth.callWebService(service, onFirstCalledWebService);
        },
        logout : function(){
            ui.hide('logout');
            ui.hideAuthSite();
            auth.removeAuthorization(onRemoveAuthorization);
        }
    };
})(); 
 
 
//Invoked when user presses 'Go!' button query YQL with user input and dumps YQL
//response to UI.
YAHOO.openmail.samples.yql.query = (function(){
    var ui = YAHOO.openmail.samples.yql.ui;
    var callWS = YAHOO.openmail.samples.yql.ws.call;
 
    function onYQL_Response(response){
        var data;
        if(response.error){
            data = '{ Result : "error querying YQL" }';
            ui.onError(response.error);
        } else{
            data = YAHOO.lang.JSON.parse(response.data);
            ui.show('logout');
            ui.renderYQL(data);
        }
    }
 
    return function(){
        ui.hide('results');
        ui.hide('error');
        callWS({ url : 'http://query.yahooapis.com/v1/yql', method: 'GET',
                 parameters : {format : 'json', q : ui.getQuery()}},
               onYQL_Response);
    };
})();
 
 
YAHOO.openmail.samples.yql.init = function(){
    YAHOO.openmail.samples.yql.ui.init();
};
 
YAHOO.util.Event.onDOMReady(YAHOO.openmail.samples.yql.init);