node.jsのPromiseでTwitter APIにアクセス

ECMAScript 6thが正式版になったのでPromiseを使ってみたい!

というわけで、Twitter APIにアクセスしてOAuth 1.0のアクセストークンをゲットするコマンドラインツールをPromiseで書いてみました。

OAuth 1.0ではアクセストークンを取得する過程で、ブラウザを開き、PinCodeを取得して入力するといった面倒な処理がありますが、そのPinCodeの入力待ちもPromiseで行っております。

nodeのバージョンはv0.12.4

var request = require('request');
var qs = require('querystring');
var readline = require('readline');
var cp = require('child_process');
var fs = require('fs');

exports.init = function(consumerInfo, file) {
    var requestInfo;

    gettingRequestToken(consumerInfo).then(function(data) {
        requestInfo = data;
        return waitingPinInput(requestInfo);
    }).then(function(pinCode) {
        return gettingAccessToken(consumerInfo, requestInfo, pinCode);
    }).then(function(accessInfo) {
        var str = JSON.stringify(accessInfo);
        fs.writeFileSync(file, str, {mode: 0600});
        console.log('Your Access Token Saved!');
        process.exit(0);
    }).catch(function(err) {
        console.error(err);
        process.exit(1);
    });
};


function gettingAccessToken(consumerInfo, requestInfo, pinCode) {
    return new Promise(function(resolved, rejected) {
        var oauth = {
            consumer_key: consumerInfo.consumer_key,
            consumer_secret: consumerInfo.consumer_secret,
            token: requestInfo.oauth_token,
            token_secret: requestInfo.oauth_token_secret,
            verifier: pinCode
        };

        var url = 'https://api.twitter.com/oauth/access_token';

        request.post({url: url, oauth: oauth}, function(err, res, body) {
            if (err) {
                rejected(err);
                return;
            }

            if (res.statusCode !== 200) {
                rejected(new Error('Not OK Response: ' + res.statusCode));
                return;
            }

            var data = qs.parse(body);

            resolved(data);
        });
    });
}


function waitingPinInput(requestInfo) {
    var AUTHORIZE_URL = 'https://api.twitter.com/oauth/authorize' +
                        '?oauth_token=';

    cp.exec('open ' + AUTHORIZE_URL + requestInfo.oauth_token);  // OSX専用

    return new Promise(function(resolved, rejected) {
        var rl = readline.createInterface({
            input: process.stdin,
            output: process.stdout
        });

        rl.question('Input Pin Code: ', function(answer) {
            resolved(answer);
        });
    });
}


function gettingRequestToken(info) {
    return new Promise(function(resolved, rejected) {
        var oauth = {
            consumer_key: info.consumer_key,
            consumer_secret: info.consumer_secret
        };

        var url = 'https://api.twitter.com/oauth/request_token';

        request.post({url: url, oauth: oauth}, function(err, res, body) {
            if (err) {
                rejected(err);
                return;
            }

            if (res.statusCode !== 200) {
                rejected(new Error('Not OK Response: ' + res.statusCode));
                return;
            }

            var data = qs.parse(body);

            resolved(data);
        });
    });
}
var token = require('./token');
token.init({
    consumer_key: "hogehoge",
    consumer_secret: "fugafuga"
}, 'token.txt')

nodeで定番のasyncに比べて便利というわけでもないですが、promiseのチェインは結構書きやすいです。