Skip to content

Instantly share code, notes, and snippets.

@lbrenman
Last active August 29, 2017 19:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lbrenman/1c73974710496a9fb877b0d86aee7848 to your computer and use it in GitHub Desktop.
Save lbrenman/1c73974710496a9fb877b0d86aee7848 to your computer and use it in GitHub Desktop.
Axway API Builder Twitter Bot Example

Axway API Builder Twitter Bot Example

A Bot is a device or piece of software that can execute commands, reply to messages, or perform routine tasks, such as online searches, either automatically or with minimal human intervention.

A Twitter Bot, for example, can automatically post tweets on a topic, retweet similar posts (e.g. based on hashtag searches) and follow other accounts that follow the bot.

This post will describe how easy it is to host a Twitter Bot on Axway's API Builder. The advantage to doing this is that the Bot will have access to API Builder services such as the NoSQL Database, APIs and connectors and Axway Mobile Backend Services. This blog post is not intended to be a tutorial on Twitter API's or building intelligent Twitter Bots but more of the mechanics of hosting a Twitter Bot on Axway API Builder.

Background

There are many articles on the web that describe how to create Twitter Bots on NodeJS. Here are a couple that I used as a starting point for this project.

In my example, I will create a simple Twitter Word Bot that does the following:

  • Tweets a random word and definition from Wordnik
  • Retweets posts that contain the hashtag #Dictionary
  • Follows users that follow the Bot

Here are some screen shots of the Bot as viewed on an iPhone. Notice the psuedo random nature of the posts and retweets as well gaps in posting.

Setup

  • Create an Arrow Project

  • Install twit npm in your Arrow project

  • Add the twit dependency to package.json

  • Set up an application on the Twitter account you want to retweet from via: https://apps.twitter.com/app/new and get your keys:

    Consumer Key (API Key)
    Consumer Secret (API Secret)
    Access Token
    Access Token Secret

    I created a new Twitter account for my Bot (@lbrenmandev). Check it out here.

  • Decide what you want to post in your tweets. I am posting a random word from Wordnik, so my next steps were to:

    • Install wordnik npm in your Arrow project
    • Add the wordnik dependency to package.json

Implementation

Typically API Builder is used to build and host microservices/APIs. In this example, we are not building APIs. Instead, we are using API Builder to run a NodeJS app.

In order to make the Twitter Word Bot execute, I create a timer that fires on the hour. The timer is added to the API Builder project's app.js file in the server.on 'started' code as follows:

var Utils = require('./lib/utils');
var constants = require('./conf/const');
var timerInterval = constants.timerPeriod;
var Arrow = require('arrow'),
	server = new Arrow();

// lifecycle examples
server.on('starting', function () {
	server.logger.debug('server is starting!');
});

server.on('started', function () {
	server.logger.debug('server started!');
	console.log('app: timer started');
	var timer = setInterval(Utils.twitBot, timerInterval);
});

// start the server
server.start();

In the code above, the timer, timer, calls the twitBot() function in the utils.js file in the lib folder. The time interval is defined in the const.js file shown below:

module.exports = {
  twitter_consumer_key: <TWITTER CONSUMER KEY>,
  twitter_consumer_secret: <TWITTER CONSUMER SECRET>,
  twitter_access_token: <TWITTER ACCESS TOKEN>,
  twitter_access_token_secret: <TWITTER ACCESS TOKEN SECRET>,
  wordnik_api_key: <WORDNIK API KEY>,
  twitBot_screen_name: 'lbrenmandev',
  timerPeriod: 3600000 // 1 hour
};

The twitBot() code is in the utils.js file in the lib folder and is shown below:

var Twit = require('twit');
var t = new Twit({
	consumer_key: constants.twitter_consumer_key,
	consumer_secret: constants.twitter_consumer_secret,
	access_token: constants.twitter_access_token,
	access_token_secret: constants.twitter_access_token_secret,
	timeout_ms: 60*1000,  // optional HTTP request timeout to apply to all requests.
});

exports.twitBot = function() {
	followFollowers(t);
	var i = getRandomIntInclusive(1,10);
	if(i<3) {
		retweet(t);
	} else if(i<6) {
		postTweet(t);
	}
};

The code above attempts to make the Bot seem more real by not performing the exact same action every hour. Here is what it does every time the timer fires:

  • Checks for followers and follows them back
  • 20% of the time, it searches tweets that include the hashtag #dictionary and retweets one
  • 30% of the time, it posts a new tweet of a random word and definition

Below is the followFollowers() function:

function followFollowers(twitbot) {
	twitbot.get('followers/list', { screen_name: constants.twitBot_screen_name }, function(err, data, response) {
		if(err) {
			console.log('utils: twitter follower list search error, err = '+JSON.stringify(err));
		} else {
			console.log('utils: twitter follower list search success');
			_.forEach(data.users, function(item){
				twitbot.post('friendships/create', { id: item.id_str }, function (err, data, response) {
					if(err) {
						console.log('utils: twitter follow error, err = '+JSON.stringify(err));
					} else {
						console.log('utils: twitter follow success');
					}
				});
			});
		}
	});
}

Here is a walk through of the code above:

  • Use the twit npm get method 'followers/list' to get a list of users following my Bot
  • Loop through (lodash forEach) the list of followers
  • Use the twit npm post method 'friendships/create' to follow each follower based on their id (item.id_str)

The code for the followFollowers(), retweet(), and postTweet() methods can be found in the utils.js file here.

Summary

In this blog post we saw how easy it is to host a Twitter Bot in Axway's API Builder.

Check the Word Bot out at https://twitter.com/lbrenmandev, follow the Bot and watch it follow you back within the hour and try creating a Twitter Bot yourself. Consider other features like:

  • Unfollowing users that unfollow you
  • Like/Favorite a tweet from a follower
  • Use Axway's connectors to easily tap into other data to tweet
  • Use Axway's NoSQL Database to store and retrieve data
var Utils = require('./lib/utils');
var constants = require('./conf/const');
var timerInterval = constants.timerPeriod;
var Arrow = require('arrow'),
server = new Arrow();
// lifecycle examples
server.on('starting', function () {
server.logger.debug('server is starting!');
});
server.on('started', function () {
server.logger.debug('server started!');
console.log('app: timer started');
var timer = setInterval(Utils.twitBot, timerInterval);
});
// start the server
server.start();
{
"name": "lbtwitterbot",
"description": "",
"version": "1.0.0",
"author": "Leor Brenman",
"license": "",
"framework": "none",
"keywords": [
"appcelerator",
"arrow"
],
"repository": {},
"private": true,
"dependencies": {
"async": "^1.5.0",
"lodash": "^3.10.1",
"pkginfo": "^0.3.1",
"twit": "^2.2.5",
"wordnik": "^0.0.2"
},
"devDependencies": {
"grunt": "^0.4.5",
"grunt-appc-js": "^1.0.19",
"grunt-contrib-clean": "^0.7.0",
"grunt-mocha-istanbul": "^3.0.1",
"istanbul": "^0.4.1",
"mocha": "^2.3.4",
"should": "^8.0.2",
"arrow": "^*",
"request": "^2.67.0",
"twit": "^2.2.5",
"wordnik": "^0.0.2",
"lodash": "^3.10.1"
},
"main": "app.js",
"healthCheck": true,
"scripts": {
"start": "appc run",
"test": "grunt"
},
"engines": {
"node": "4.2.0"
}
}
var Arrow = require('arrow');
var constants = require('../conf/const');
var _ = require('lodash');
var Twit = require('twit');
var t = new Twit({
consumer_key: constants.twitter_consumer_key,
consumer_secret: constants.twitter_consumer_secret,
access_token: constants.twitter_access_token,
access_token_secret: constants.twitter_access_token_secret,
timeout_ms: 60*1000, // optional HTTP request timeout to apply to all requests.
});
exports.twitBot = function() {
console.log('utils: twitBot() called');
followFollowers(t); // follow anyone who is following me
var i = getRandomIntInclusive(1,10);
// console.log('utils: i = '+i);
if(i<3) { // 20% of the time retweet
// console.log('utils: i < 3 so retweet()');
retweet(t);
} else if(i<6) { // 30% of the time post a random word
// console.log('utils: 2 < i < 6 so postTweet()');
postTweet(t);
} else { // 50% of the time do nothing
// console.log('utils: 5 < i so do nothing');
}
};
function followFollowers(twitbot) {
console.log('utils: followFollowers() called');
twitbot.get('followers/list', { screen_name: constants.twitBot_screen_name }, function(err, data, response) {
if(err) {
console.log('utils: twitter follower list search error, err = '+JSON.stringify(err));
} else {
console.log('utils: twitter follower list search success');
// console.log('data = '+JSON.stringify(data));
_.forEach(data.users, function(item){
// console.log('item = '+JSON.stringify(item));
twitbot.post('friendships/create', { id: item.id_str }, function (err, data, response) {
if(err) {
console.log('utils: twitter follow error, err = '+JSON.stringify(err));
} else {
console.log('utils: twitter follow success');
}
});
});
}
});
}
function getRandomIntInclusive(min, max) {
// console.log('utils: getRandomIntInclusive() called');
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function retweet(twitbot) {
console.log('utils: retweet() called');
twitbot.get('search/tweets', { q: '#dictionary' }, function(err, data, response) {
if(err) {
console.log('utils: twitter search error');
} else {
console.log(data.statuses[0]);
twitbot.post('statuses/retweet/:id', { id: data.statuses[0].id_str }, function (err, data, response) {
if(err) {
console.log('utils: twitter retweet error, err = '+JSON.stringify(err));
} else {
console.log('utils: twitter retweet success');
}
});
}
});
}
function postTweet(twitbot) {
console.log('utils: postTweet() called');
var Wordnik = require('wordnik');
var wn = new Wordnik({
api_key: constants.wordnik_api_key
});
wn.randomWord({"hasDictionaryDef":true},function(e, word) {
// console.log(e, word);
if(e) {
console.log('utils: wordnik random word error = '+e);
} else {
console.log('utils: wordnik random word = '+JSON.stringify(word));
// Note that i need to encodeURIComponent the random word because sometimes it's
// two words (e.g. Native American) and the space causes an exception below
wn.definitions(encodeURIComponent(word.word), function(e, defs) {
// console.log(e, defs);
if(e) {
console.log('utils: wordnik word definition error = '+JSON.stringify(e));
} else {
console.log('utils: wordnik word definition = '+JSON.stringify(defs));
var status='Random word is "'+defs[0].word+'", with definition: "'+defs[0].text+'"';
console.log('utils: '+status);
twitbot.post('statuses/update', { status: status }, function(err, data, response) {
if(err) {
console.log('utils: twitter post error err = '+JSON.stringify(err));
} else {
console.log('utils: twitter post success');
}
});
}
});
}
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment