前回のサンプルアプリをちょっと時間が経ってから動かしてみると、
[ERROR] In the error handler looking for a 401, and have a 401
[ERROR] Handleing the 401 error...
とかエラーが出てしまい動きません…
force.comからOAuth2で取得したaccess tokenには有効期限があるのでrefresh tokenを使って再度取得する必要があるのですが…そこが動作していないようです。
※
force.comのOAuthについて詳しくはこちらで
エラーのコールバックも呼んでくれないので有効期限切れたかどうかも検出できず…
なんとかhackできないかと、こんな感じでモジュールの中身をダンプしてみます。
var FDC = require('com.salesforce');
for (var i in FDC.ForceOAuth) {
Ti.API.debug(i + ':' + FDC.ForceOAuth[i]);
}
最終的にREST APIの呼び出しはここに来るようです。
[DEBUG] makeRestCall:function (path, callback, error, method, payload, retry) {var restUrl=Ti.Network.decodeURIComponent(fa.instanceUrl)+'/services/data'+path;var xhr=Ti.Network.createHTTPClient();xhr.onload=function(){Ti.API.info("REST Response: "+this.responseText);var data="";if(this.responseText){data=this.responseText;}
callback(data);};xhr.onerror=function(e){Ti.API.error("XHR, error handler..."+"\nDbDotCom.REST.OAuth.refreshToken: "+fa.refreshToken+"\nretry: "+retry+"\n e: "+e.error+"\nXHR status: "+this.status);if(!fa.refreshToken||retry){error(e.error);}else{Ti.API.error("In the error handler looking for a 401, and have a "+xhr.status);if(xhr.status===401){Ti.API.error("Handleing the 401 error...");exports.refreshAccessToken(function(oauthResponse){Ti.API.error("Refresh response... "+oauthResponse);fa.makeRestCall(path,callback,error,method,payload,true);},error);}else{Ti.API.error("Not a 401 error, re-throwing...");error(e);}}};if(fa.usePostBin===true){restUrl="http://www.postbin.org/135onm5";}
xhr.open(method||"GET",restUrl,true)
Ti.API.info("Rest url: "+restUrl);xhr.setRequestHeader("Authorization","OAuth "+Ti.Network.decodeURIComponent(fa.accessToken));xhr.setRequestHeader("Content-Type","application/json");xhr.send(payload);}
出てるログから、exports.refreshAccessToken()の呼び出しの中でエラーが起きてコールバックまで戻って来ないようです。
よく考えたら、OAuth2のrefresh tokenによるaccess token再取得時にはclient secretが必要なはずなのに、モジュールのパラメータなどでどこにもセットしていないのでrefreshできるわけないですね… 未実装なんでしょうか?
※追記:secret要らない仕様に変わってました
ダンプしたソースを参考に、
こんな感じでhackしてみました。
※モジュール内で定義されてるobjectのプロパティは動的に書き換えられない?&スコープ的にアクセスできない変数があったので結構無理矢理
使い方は、requireした後にこのファイルをincludeしてパッチを当て、ForceOAuthの代わりにForceOAuth2を使うようにします。ForceOAuth2.openのパラメータにはclient id
とclient secretを渡す様にします。
var FDC = require('com.salesforce');
Ti.include('fdc-patch.js');
FDC.ForceOAuth2.open('CLIENT_ID');
パッチしたポイントは2つ。refreshAccessTokenを
client secretを使用して動作する様にしたのと、
REST APIのパスの固定部分に /data が含まれていたのを /apexrest が呼べる様に /services までとしたこと。
Winter '12でリリースされたApex RESTを使って公開したAPIのURLは、$instance_url/services/apexrest/... となるので、FDC.ForceOAuth2.makeRestCall('/apexrest/myapi', callback) の様な感じで使える様になります。
marketplaceのモジュールのページには、"This toolkit is maintained by the community and sponsored by salesforce.com. Salesforce.com does not officially support this product."とか書いてあるんですが、
パッチとか提供したい場合どこに連絡すればいいんでしょうか… githubとかにソース上がってればforkするのに…
この記事は
Force.com Advent Calendar 2011に参加しています。