How I Made a Twitterbot with Node.js

The other day, I decided to make a Twitterbot to help streamline my marketing efforts for my art brand. I wanted to make a bot that would retweet tweets from a different user, selected from a list of users. I wanted the bot to also run once a day.

For my project, I used the following:

  • Node.js
  • twit – Twitter API client for Node.js
  • Heroku – platform for deployed applications

Creating an Application with Twitter

To get started, I used the Twitter application form to register my application. The process is pretty straight forward, and once it was completed, I was able to grab the necessary consumer_key, consumer_secret, access_token, and access_token_secret.

Building the Bot

To get started with Node.js, I created a new project directory. Then I ran npm init.

I ran the following commands to ensure I had the right packages to build the application:

npm install --save dotenv http twit

Next, I created the environment variables. I created a .env file in the directory, where I added in my project keys:

CONSUMER_KEY="add_it_here"
CONSUMER_SECRET="add_it_here"
ACCESS_TOKEN="add_it_here"
ACCESS_TOKEN_SECRET="add_it_here"

In my index.js file, I connected the .env variables to the application:

require("dotenv").config();
const config = {
  consumer_key: process.env.CONSUMER_KEY,
  consumer_secret: process.env.CONSUMER_SECRET,
  access_token: process.env.ACCESS_TOKEN,
  access_token_secret: process.env.ACCESS_TOKEN_SECRET
};

Then I added logic so the bot would retweet tweets from a list of users or retweet tweets tied to specific hashtags. First I set variables to use twit and to control the number of retweets the bot would make when the code was executed:

const twit = require("twit");
const Twitter = new twit(config);
const MAX_RT_COUNT = 1;

I found the Twitter ids for several users that I wanted to the bot to retweet. I used their ids instead of their screen names, in case a user decided to change their screen name. In order to keep track of who was who, I stored details about each user in a comment:

const USERS = [
  "15057943", // moma
  "14803372", // saam
  "5225991", // tate
  "22009731", // design museum
  "81783051", // artsy
  "17896874", // itsnicethat
  "158865339", // fastcodesign
  "21661279", // creative review
  "16336998", // print magazine
  "17623957", // design observer
  "418597196", // creativebloq
  "15446126", // design milk
  "18201801", // interior design
  "19038849" // how design
];

I made a function that would filter through the list of users, so that each day of the week, a different user would get a retweet from the bot:

const getUserOfTheDay = () => {
  let date = new Date();
  let dayOfMonth = date.getDate();
  let pickUserIndex = dayOfMonth % USERS.length;
  return USERS[pickUserIndex];
};

Next, I created the logic for retweeting tweets tied to different hashtags. I ultimately decided not to deploy this functionality, but I wanted to keep it around in case it’s useful in the future:

let retweetTags = async function() {
  try {
    const { data } = await Twitter.get("search/tweets", {
      q: "#art, #painting",
      result_type: "mixed",
      lang: "en"
    });

    const statuses = data.statuses.slice(0, MAX_RT_COUNT);
    // loop through the first n returned tweets
    for (const status of statuses) {
      // the post action
      const response = await Twitter.post("statuses/retweet/:id", {
        id: status.id_str
      });
      if (response) {
        console.log("Successfully retweeted");
      }
    }
  } catch (err) {
    // catch all log if the search/retweet could not be executed
    console.error("Err:", err);
  }
};

// retweetTags();

Lastly, I added the code for retweeting tweets from my list of users:

let retweetUsers = async function() {
  try {
    const { data } = await Twitter.get("users/show", {
      user_id: getUserOfTheDay()
    });

    const status = data.status;
    // make sure tweet isn't in reply to another user
    if (status.in_reply_to_status_id == null) {
      const response = await Twitter.post("statuses/retweet/:id", {
        id: status.id_str
      });
      if (response) {
        console.log("Successfully retweeted");
      }
    }
  } catch (err) {
    // catch all log if the search/retweet could not be executed
    console.error("Err:", err);
  }
};

To run the bot locally, I added retweetUsers(); to the file, then ran node index.js in the terminal.

Deploying the App to Heroku

Once I had my app up and running locally, I wanted to deploy it somewhere so it could run automatically. I did this by deploying it to Heroku.

I added a Procfile to the project, and added the line worker: node index.js to the file. Then I created a new Heroku project by running heroku create twitterbot-retweet. Next, I had to define the environment variables in Heroku by running heroku set:config key_name="key_value" in the terminal.

By accessing the Heroku dashboard online, I had to toggle on the worker for the bot (it was located under the “Dyno formation” section).

After deploying the bot, I realized I wanted the bot to run once every day, so I looked into options for how I could wake the application up once a day in order to execute the code. I ended up going with the simple setInterval method.

If your curious about how all the code looks, or want to see an up-to-date version of the project, you can find it on GitHub.

How to Add a Script to Minify your JavaScript in a package.json file

Recently I was working on a project where I wanted to set up a process that could combine and minify the JavaScript I had in a specific folder for a project. So how did I do it?

I decided to run the npm init command on my project folder. Within the package.json file, I had the following:

{
  "main": "scripts.js",
  "scripts": {
  "minify": "uglifyjs ./js/* -o scripts.min.js",
  "uglify": "npm run minify"
},
  "dependencies": {
  "uglify-js": "^2.8.8"
},
  "devDependencies": {
  "uglify-js": "^2.8.8"
 }
}

Once I ran npm install uglify-js --save, I made sure to specify the folder I wanted to run the process in (./js/*), and the file I wanted to create with the minified code (scripts.min.js). Next, all I had to do was run npm run uglify and my new scripts.min.js minified file was created.

Now whenever I make changes or add new files to my project’s JavaScript folder, I can run npm run uglify to bundle up and minify the code.

A Brief Overview of ES6

ECMAScript 6, or ES6, is a newer version of JavaScript. It has several unique capabilities that weren’t possible in previous versions of JavaScript, for example:

  • Variables can be set with the terms let and const
  • The let keyword is used for block scoping so it doesn’t affect global values
  • The const keyword is used to protect the value of certain variables – you use this keyword for values that shouldn’t be reassigned
  • It allows you to use template strings to tap into the functionality of template languages to format your JavaScript code with variables like so: `${yourVariableHere}`
  • The spread operator can turn elements of an array into arguments of a function call or into elements of an array literal
  • Allows us to make classes in JavaScript (can create one super class that other classes inherit)
  • Can pass default values in functions for when you don’t explicitly pass anything for them

In order for browsers to understand ES6, you need to transpile the code. Babel, Traceur, and Closure are used for transpiling code, although Babel is known for supporting the most ES6 features.

For larger scale projects, you can use build tools like Webpack with ES6 – this allows us to load our dependencies. Npm creates a package.json file that runs dependencies.

 

Yarn: the JavaScript Package Manager

If you already use npm, you’re probably wondering what’s the point of Yarn?

Yarn is a somewhat new JavaScript package manager created by the engineers at Facebook.

  • It’s a faster and more secure dependency manager
  • It uses an offline cache – so after you’ve installed a package using Yarn, it will be available on your machine for offline access.

Quite honestly, what really reeled me in with Yarn was the speed at which it can install packages. It’s amazing how shaving off a few seconds from installing packages can really speed up your overall workflow.

Get Yarn

npm install –g yarn

Or use brew to add it. Once installed, you use the following format to add any dependency:

yarn add <name of package>

A Brief Overview of React.js

React is a user interface library that was developed at Facebook. React is written in different components and follows the principles of immutable data. It’s often used in enterprise applications, and it makes creating single page applications easier since they have a higher speed thanks to the virtual DOM. This means it writes to the browser DOM only when it is needed, instead of re-rendering an entire view when a change is made.

Virtual DOM

React creates an in-memory DOM where it only renders different parts of the DOM when a change occurs.

JSX

React utilizes JSX, which is a JavaScript extension syntax that allows you to quote HTML.

Babel

Babel is a transpiler that transpiles JavaScript code. It works for JSX as well as ES6 and beyond. Babel converts React’s JSX and ES6 to something the browser can use.

Components

React applications consist of a collection of components. Components are small user interface elements that display data as it changes over time. Used together, these components create entire user interfaces.

Component Lifecycle

Component lifecycles allow you to add libraries and load data at specific times. They also help improve the speed of an application, with lifecycle methods that you can override to run code a specific times in the process.

Mounting methods are called when an instance of a component is being created:

  • getInitialState()
  • componentWillMount()
  • componentDidMount()

Updating methods occur when a change happens to props or state:

  • componentWillReceiveProps()
  • shouldComponentUpdate()
  • componentWillUpdate()
  • render()
  • componentDidUpdate()

Unmounting methods are called when a component is being removed:

  • componentWillUnmount()

 

A Brief Overview of Node.js and Express.js

If you’ve worked with JavaScript frameworks and libraries, chances are that you’ve heard of Node.js and Express.js. So for those who are unfamiliar to these terms – what exactly are they?

Node.js

Node.js is an open-source JavaScript runtime environment, that uses Google’s V8 JavaScript engine, where you can build server applications. Node.js is not a framework, although it has many modules that are written in JavaScript. It has event-driven architecture that is capable of asynchronous I/O, otherwise none as a form of input/output processing that allows other processing to continue before the transfer of data has finished.

Express.js

Express.js is a web application framework for Node.js, that’s used for building APIs. It is also known for being a backend component of the MEAN stack.

I’ve worked with Node.js and Express.js to create APIs, so I feel like I can never think about one of them without having the other one come to mind.

JavaScript: What’s the point of looping?

In JavaScript, looping is a handy way to do something repeatedly. For example, if you wanted to print out a list of results in a consistent way, or add styles to objects that fit certain parameters.

Here are a few of the ways to do looping:

for statement

A for statement is usually used when you need to increment a value within an expression.

for (var i = 0; i > 10; i++) {
console.log(i);
}

do…while statement

A do…while statement repeats until a specific condition evaluates to false.

var i = 10;
do {
i++;
console.log(i);
} while (i < 40);

while statement

A while statement executes as long as a specified condition evaluates to true.

var i = 2;
while (i < 5) {
i++;
console.log(i);
}

break statement

The break statement is used to terminate a loop.

for (var i = 0; i < a.length; i++) {
if (a[i] == 5) {
break;
}
}

Note: This post is written in conjunction with the coding cheat sheets I’m developing.

JavaScript: What are Closures?

So maybe you’ve heard of JavaScript closures before but you’re wondering, what exactly are they? Well, when it comes to JavaScript, you can have variables that belong to a local (a variable declared within a specific function) or global scope (variables that are accessible from anywhere in the code). You can make variables private by using closures.

Take a look at the following example:

var countUp = (function () {
var count = 0;
return function () {return count += 1;}
})();

countUp();

Now, let’s break it down:

  • The variable countUp is assigned the value of a self-invoking function.
  • It sets the count to 0 and returns a value that adds 1 to the current count.
  • It has access to the count in the parent scope.
  • The variable count is protected by the scope of the anonymous function, and can only be changed using the countUp function.

Yoda Speak

I can’t believe it’s been nearly three weeks since I completed the WDI course. In an effort to make sure I’m staying sharp with my coding skills, I’m going to try to complete coding challenges every week and create a new app every month. Will I succeed with living up to those goals? I sure hope so!

I am also combing through my previous class assignments from WDI to try to find ways to refactor my code or polish existing work into more functional applications. So recently I decided to revisit a Yoda exercise we did. Using vanilla JavaScript, I created an application that utilizes the Yoda Mashape API for translating text into Yoda speak.

You can view the live app here and see the Github repo over here.

Yoda Speak

WDI Day Fifty-Eight: Project 4 Presentations and the Last Day of WDI

I can’t believe that three months have already gone by, and that WDI is over. It was a wonderful experience and I’m glad I decided to go through it. Today we had a chance to work on our projects in the morning, and in the afternoon we presented our project 4. I was pleasantly surprised that a lot of people enjoyed my application. I thought it was a rough project that wasn’t fully complete, but it was great seeing that others thought it was good.

After our presentations, we did a few group activities to close off our experience at WDI. We did an exercise where we had a piece of paper taped to our back and everyone walked around writing things we liked about other people so they were receiving anonymous compliments. A couple of the students in the class created certificates for everyone that were pretty humorous. We also received GA backpacks and did a toast at the end of class.

Overall, the experience has been a really positive one. I doubted myself a lot at times towards the end of the course, but overall I did indeed learn a lot. I also met such a wonderful group of people who I hope I can stay in touch with for years.