For the most part, working in an OAuth2 Twitter-only app using Chris Q's promise library with https.request , the Nodejs Express api route. The first attempt at a custom GET timeline. If the answer is 401, updating the carrier token, try the user again. I had to use Q.when to fulfill a promise that returns another promise (chain) or value.
/** * Using Rails-like standard naming convention for endpoints. * GET /things -> index * POST /things -> create * GET /things/:id -> show * PUT /things/:id -> update * DELETE /things/:id -> destroy */ 'use strict'; // var _ = require('lodash'); var http = require('http'); var https = require('https'); var querystring = require('querystring'); var Q = require('q') // Get list of twtimelines exports.index = function(req, res) { var tid = req.query.tid if (tid) { Q.when(reqTimeline(tid, true, res), function(value) { // > value // 404 // > body1 // '{"errors":[{"code":34,"message":"Sorry, that page does not exist."}]}' }) } else { res.json({ errors: [{ message: 'no tid specified in query' }] }); } }; function reqPromise(options, postData) { var deferred = Q.defer() var req = https.request(options, function(res) { // console.log("statusCode: ", res.statusCode); // console.log("headers: ", res.headers); var statusCode = res.statusCode deferred.notify(res) res.on('data', function(d) { //process.stdout.write(d); deferred.notify(d) }).on('end', function() { deferred.resolve(statusCode) }); }); req.on('error', function(e) { console.error(e); deferred.reject(e) }); req.write(postData); req.end(); return deferred.promise } // deferRequest function isIncomingMessage(ot) { return ot instanceof http.IncomingMessage } function isBuffer(ot) { return ot instanceof Buffer } function reqTimeline(screen_name, reqBearerTokenOn401, res) { var optionsUserTimeline = { hostname: 'api.twitter.com', path: '/1.1/statuses/user_timeline.json?' + querystring.stringify({ count: '3', screen_name: screen_name }), method: 'GET', headers: { //'Authorization': 'Bearer ' + JSON.parse(body1).access_token 'Authorization': 'Bearer ' + process.env.BEARER_TOKEN } // headers }; console.log("optionsUserTimeline", optionsUserTimeline) var statusCode; var body1 = new Buffer(''); // default utf8 string buffer ? return reqPromise(optionsUserTimeline, '') .then(function(value) { // done if (reqBearerTokenOn401 && value === 401) { console.log("reqTimeline - requesting bearer token") return reqBearerToken(screen_name, res) } console.log("reqTimeline - done done:", value) res.end() return value }, function(reason) { // error console.log("reqTimeline - error:", body1) }, function(progress) { console.log("reqTimeline - progress:", body1) if (isIncomingMessage(progress)) { body1 = body1.slice(0, 0) // re-set buffer statusCode = progress.statusCode; if (reqBearerTokenOn401 && statusCode === 401) { // readyn for retry } else { res.writeHead(statusCode) } } else if (isBuffer(progress)) { if (reqBearerTokenOn401 && statusCode === 401) { body1 += progress } else { res.write(progress) } } else { throw "reqTimeline - unexpected progress" } }); } // reqTimeline function reqBearerToken(screen_name, res) { var postData = querystring.stringify({ 'grant_type': 'client_credentials' }) var optionsBearerToken = { hostname: 'api.twitter.com', path: '/oauth2/token', method: 'POST', headers: { 'Authorization': 'Basic ' + new Buffer( process.env.CONSUMER_KEY + ":" + process.env.CONSUMER_SECRET ).toString('base64'), 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', 'Content-Length': postData.length } // headers } // console.log("key", process.env.CONSUMER_KEY) // console.log("secret", process.env.CONSUMER_SECRET) // console.log("buf", new Buffer( // process.env.CONSUMER_KEY + ":" + process.env.CONSUMER_SECRET // ).toString()) console.log("optionsBearerToken", optionsBearerToken) var body2 = new Buffer(''); // default utf8 string buffer ? return reqPromise(optionsBearerToken, postData) .then(function(value) { // done console.log("reqBearerToken - done:", body2) if (value === 200) { console.log("reqBearerToken - done done") process.env.BEARER_TOKEN = JSON.parse(body2).access_token; return reqTimeline(screen_name, false, res) } return value }, function(reason) { throw "reqBearerToken - " + reason }, function(progress) { if (isIncomingMessage(progress)) { body2 = body2.slice(0, 0) // reset buffer } else if (isBuffer) { body2 += progress } else { throw "reqBearerToken - unexpected progress" } }); } // reqBearerToken