こんにちは、Juntechです。
前回の記事ではTwitter APIをAPIクライアントから叩いてみました。
せっかくAPIを使えるようになったのに、
APIクライアントから手動で実行しているだけではお得感がないですよね。
ということで今回は、
GASことGoogle Apps Scriptを使ってAPIを叩いてみたいと思います!
早速コード
こちらです。
function getTimeline(){
var url = "https://api.twitter.com/1.1/statuses/usevr_timeline.json?screen_name=takapon_jp";
var method = 'GET'
Logger.log(encodeURIComponent(url))
execute(url,method)
}
function tweet(){
var tweet = "GASからツイートしてみた!"
var url = "https://api.twitter.com/1.1/statuses/update.json?status="+tweet;
var method = 'POST';
execute(url,method)
}
function execute(url,method,body) {
// プロパティ取得
var CONSUMER_KEY = PropertiesService.getScriptProperties().getProperty('consumer_key');
var CONSUMER_SECRET = PropertiesService.getScriptProperties().getProperty('consumer_secret');
var ACCESS_TOKEN = PropertiesService.getScriptProperties().getProperty('access_token');
var TOKEN_SECRET = PropertiesService.getScriptProperties().getProperty('token_secret');
// 認証情報作成
var date = new Date();
var timestamp = date.getTime().toString().substr(0,10);
var nonce = timestamp; // 実行毎に一意であれば何でもいい
var authorizationParameters = [
'oauth_consumer_key=' + CONSUMER_KEY,
'oauth_nonce=' + nonce,
'oauth_signature_method=HMAC-SHA1',
'oauth_timestamp=' + timestamp,
'oauth_token=' + ACCESS_TOKEN,
'oauth_version=1.0'
];
var encodedUrl = encodeURI(url)
var baseUrl = encodedUrl
var queryParams = new Array();
if(encodedUrl.match(/\?/)){
baseUrl = encodedUrl.split('?')[0]
queryParams = encodedUrl.split('?')[1].split('&')
queryParams.forEach(function(param){
authorizationParameters.push(param);
})
authorizationParameters = authorizationParameters.sort()
Logger.log(queryParams)
}
// Signature作成
var signature_base_string = method + '&' + encodeURIComponent(baseUrl) + '&' + encodeURIComponent(authorizationParameters.join('&'));
var signature_key = encodeURI(CONSUMER_SECRET) + '&' + encodeURI(TOKEN_SECRET);
var signature = encodeURIComponent(Utilities.base64Encode(Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_1, signature_base_string, signature_key)));
var authorization = 'OAuth ' + authorizationParameters.join(',') + ',oauth_signature=' + signature;
// APIパラメータ作成
var parameters = {
method : method,
headers : {"Authorization": authorization},
muteHttpExceptions : true
};
// API実行
var response = UrlFetchApp.fetch(encodedUrl,parameters);
return response
}
前回同様、
自分のタイムラインを取得するやつと、ツイートするやつを作ってみました。
見ての通り、まずはOAuth1a版で作成しています。
気分が乗ったらOAuth2版も作ろうと思います。
executeの解説
スクリプトプロパティ
まずはこの部分。
// プロパティ取得
var CONSUMER_KEY = PropertiesService.getScriptProperties().getProperty('consumer_key');
var CONSUMER_SECRET = PropertiesService.getScriptProperties().getProperty('consumer_secret');
var ACCESS_TOKEN = PropertiesService.getScriptProperties().getProperty('access_token');
var TOKEN_SECRET = PropertiesService.getScriptProperties().getProperty('token_secret');
GASには、スクリプトプロパティといって、環境変数みたいなものをセットできる機能があります。
これを使って、ソースコードには認証キーなどを持たせない作りにしています。
スクリプトプロパティは、ファイル -> プロジェクトのプロパティ から設定できます。
認証情報作成
ここが難関ですね。
// 認証情報作成
var date = new Date();
var timestamp = date.getTime().toString().substr(0,10);
var nonce = timestamp; // 実行毎に一意であれば何でもいい
var authorizationParameters = [
'oauth_consumer_key=' + CONSUMER_KEY,
'oauth_nonce=' + nonce,
'oauth_signature_method=HMAC-SHA1',
'oauth_timestamp=' + timestamp,
'oauth_token=' + ACCESS_TOKEN,
'oauth_version=1.0'
];
var encodedUrl = encodeURI(url)
var baseUrl = encodedUrl
var queryParams = new Array();
if(encodedUrl.match(/\?/)){
baseUrl = encodedUrl.split('?')[0]
queryParams = encodedUrl.split('?')[1].split('&')
queryParams.forEach(function(param){
authorizationParameters.push(param);
})
authorizationParameters = authorizationParameters.sort()
Logger.log(queryParams)
}
// Signature作成
var signature_base_string = method + '&' + encodeURIComponent(baseUrl) + '&' + encodeURIComponent(authorizationParameters.join('&'));
var signature_key = encodeURI(CONSUMER_SECRET) + '&' + encodeURI(TOKEN_SECRET);
var signature = encodeURIComponent(Utilities.base64Encode(Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_1, signature_base_string, signature_key)));
var authorization = 'OAuth ' + authorizationParameters.join(',') + ',oauth_signature=' + signature;
OAuth1では、下記の情報をヘッダにつけて送ります。
項目 | 中身 |
---|---|
oauth_consumer_key | Twitterアプリの認証キー |
oauth_nonce | リクエストごとに一意となる文字列。タイムスタンプとかでおk |
oauth_signature_method | 署名の作成形式。OAuth1はだいたいHMAC-SHA1 |
oauth_timestamp | タイムスタンプ |
oauth_token | Twitterで取得したアクセストークン |
oauth_version | 1.0 |
oauth_signature | 上6つとシークレットキーとかURLとか、各種パラメータをゴニョって作る署名 |
oauth_signature
のゴニョりっぷりについてはこちらを参考にしました。
https://developer.yahoo.co.jp/other/oauth/signinrequest.html
地味に厄介だったのがクエリパラメータです。
signatureを作成する際、
クエリパラメータとoauth...
をアルファベット順でソートしてつなげる必要があるため、
リストに詰めてソートをかけています。
API実行
ここは、GASでAPI叩く時のお決まりみたいなところです。
// APIパラメータ作成
var parameters = {
method : method,
headers : {"Authorization": authorization},
muteHttpExceptions : true
};
// API実行
var response = UrlFetchApp.fetch(encodedUrl,parameters);
return response
muteHttpExceptions
は、
API実行時にエラーが発生しても無視してレスポンスを返してくれるというものです。
叩いてみる
それでは叩いてみましょう!
まずはgetTimeline
から。
取得結果をログ出力しています。
こんな感じ!
GASでは時間指定で起動するようにトリガーを設定できるので、
これとスプレッドシートを合わせることで、
ツイートを溜めておいて時間起動でツイートすることも可能になります!
ちなみに連続で実行してみましたが、
ツイート内容が同一だと無視されるようです。
こんなエラーが返されます。
{"errors":[{"code":187,"message":"Status is a duplicate."}]}
今回はここまで。
これからはこの技術を使って、
実用的な機能をたくさん装着していきます!